From e54398b85639b1683c0c76419a2162e8c5713b1f Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sat, 29 Nov 2025 03:24:38 +0530 Subject: [PATCH 1/5] fix: GET token-auth-token endpoint --- backend/src/lib/api-docs/constants.ts | 1 - .../routes/v1/identity-token-auth-router.ts | 6 +- .../identity-token-auth-service.ts | 56 ++++++++++++------- .../identity-token-auth-types.ts | 1 - .../endpoints/token-auth/get-token.mdx | 4 ++ 5 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 docs/api-reference/endpoints/token-auth/get-token.mdx diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 970f9a1a0..6af683c83 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -595,7 +595,6 @@ export const TOKEN_AUTH = { limit: "The number of tokens to return." }, GET_TOKEN: { - identityId: "The ID of the machine identity to get the token for.", tokenId: "The ID of the token to get metadata for." }, CREATE_TOKEN: { diff --git a/backend/src/server/routes/v1/identity-token-auth-router.ts b/backend/src/server/routes/v1/identity-token-auth-router.ts index d7cd86330..ff45778b6 100644 --- a/backend/src/server/routes/v1/identity-token-auth-router.ts +++ b/backend/src/server/routes/v1/identity-token-auth-router.ts @@ -410,7 +410,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider server.route({ method: "GET", - url: "/token-auth/identities/:identityId/tokens/:tokenId", + url: "/token-auth/tokens/:tokenId", config: { rateLimit: readLimit }, @@ -425,7 +425,6 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider } ], params: z.object({ - identityId: z.string().describe(TOKEN_AUTH.GET_TOKEN.identityId), tokenId: z.string().describe(TOKEN_AUTH.GET_TOKEN.tokenId) }), response: { @@ -436,7 +435,6 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, handler: async (req) => { const { token, identityMembershipOrg } = await server.services.identityTokenAuth.getTokenAuthTokenById({ - identityId: req.params.identityId, tokenId: req.params.tokenId, actor: req.permission.type, actorId: req.permission.id, @@ -451,7 +449,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider event: { type: EventType.GET_TOKEN_IDENTITY_TOKEN_AUTH, metadata: { - identityId: token.identityId, + identityId: identityMembershipOrg.identity.id, identityName: identityMembershipOrg.identity.name, tokenId: token.id } diff --git a/backend/src/services/identity-token-auth/identity-token-auth-service.ts b/backend/src/services/identity-token-auth/identity-token-auth-service.ts index bdc8ab1c1..a8e129511 100644 --- a/backend/src/services/identity-token-auth/identity-token-auth-service.ts +++ b/backend/src/services/identity-token-auth/identity-token-auth-service.ts @@ -621,48 +621,64 @@ export const identityTokenAuthServiceFactory = ({ const getTokenAuthTokenById = async ({ tokenId, - identityId, isActorSuperAdmin, actorId, actor, actorAuthMethod, actorOrgId }: TGetTokenAuthTokenByIdDTO) => { - await validateIdentityUpdateForSuperAdminPrivileges(identityId, isActorSuperAdmin); + const foundToken = await identityAccessTokenDAL.findOne({ + [`${TableName.IdentityAccessToken}.id` as "id"]: tokenId, + [`${TableName.IdentityAccessToken}.authMethod` as "authMethod"]: IdentityAuthMethod.TOKEN_AUTH + }); + if (!foundToken) throw new NotFoundError({ message: `Token with ID ${tokenId} not found` }); const identityMembershipOrg = await membershipIdentityDAL.getIdentityById({ scopeData: { scope: AccessScope.Organization, orgId: actorOrgId }, - identityId + identityId: foundToken.identityId }); - if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` }); + if (!identityMembershipOrg) { + throw new NotFoundError({ message: `Failed to find identity with ID ${foundToken.identityId}` }); + } + + await validateIdentityUpdateForSuperAdminPrivileges(foundToken.identityId, isActorSuperAdmin); if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) { throw new BadRequestError({ message: "The identity does not have Token Auth" }); } - const { permission } = await permissionService.getOrgPermission({ - scope: OrganizationActionScope.Any, - actor, - actorId, - orgId: identityMembershipOrg.scopeOrgId, - actorAuthMethod, - actorOrgId - }); - ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity); - const token = await identityAccessTokenDAL.findOne({ - [`${TableName.IdentityAccessToken}.id` as "id"]: tokenId, - [`${TableName.IdentityAccessToken}.authMethod` as "authMethod"]: IdentityAuthMethod.TOKEN_AUTH, - [`${TableName.IdentityAccessToken}.identityId` as "identityId"]: identityId - }); + if (identityMembershipOrg.identity.projectId) { + const { permission } = await permissionService.getProjectPermission({ + actionProjectType: ActionProjectType.Any, + actor, + actorId, + projectId: identityMembershipOrg.identity.projectId, + actorAuthMethod, + actorOrgId + }); - if (!token) throw new NotFoundError({ message: `Token with ID ${tokenId} not found` }); + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionIdentityActions.Read, + subject(ProjectPermissionSub.Identity, { identityId: identityMembershipOrg.identity.id }) + ); + } else { + const { permission } = await permissionService.getOrgPermission({ + scope: OrganizationActionScope.Any, + actor, + actorId, + orgId: identityMembershipOrg.scopeOrgId, + actorAuthMethod, + actorOrgId + }); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity); + } - return { token, identityMembershipOrg }; + return { token: foundToken, identityMembershipOrg }; }; const updateTokenAuthToken = async ({ diff --git a/backend/src/services/identity-token-auth/identity-token-auth-types.ts b/backend/src/services/identity-token-auth/identity-token-auth-types.ts index fdecc6d4c..4e7f2a499 100644 --- a/backend/src/services/identity-token-auth/identity-token-auth-types.ts +++ b/backend/src/services/identity-token-auth/identity-token-auth-types.ts @@ -42,7 +42,6 @@ export type TGetTokenAuthTokensDTO = { export type TGetTokenAuthTokenByIdDTO = { tokenId: string; - identityId: string; isActorSuperAdmin?: boolean; } & Omit; diff --git a/docs/api-reference/endpoints/token-auth/get-token.mdx b/docs/api-reference/endpoints/token-auth/get-token.mdx new file mode 100644 index 000000000..69bc14cdc --- /dev/null +++ b/docs/api-reference/endpoints/token-auth/get-token.mdx @@ -0,0 +1,4 @@ +--- +title: "Get Token" +openapi: "GET /api/v1/auth/token-auth/tokens/{tokenId}" +--- From 5f66583feaba61333867f86204bbcceba0aaff5e Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Sat, 29 Nov 2025 03:29:58 +0530 Subject: [PATCH 2/5] feat: adds copy token id button --- .../ViewIdentityAuthModal/IdentityTokenAuthTokensTable.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/IdentityTokenAuthTokensTable.tsx b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/IdentityTokenAuthTokensTable.tsx index d0d0b0fcd..5d7bf30e9 100644 --- a/frontend/src/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/IdentityTokenAuthTokensTable.tsx +++ b/frontend/src/pages/organization/IdentityDetailsByIDPage/components/ViewIdentityAuthModal/IdentityTokenAuthTokensTable.tsx @@ -22,6 +22,7 @@ import { Tooltip, Tr } from "@app/components/v2"; +import { CopyButton } from "@app/components/v2/CopyButton"; import { OrgPermissionIdentityActions, OrgPermissionSubjects, @@ -153,6 +154,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
+ Date: Tue, 2 Dec 2025 00:36:41 +0530 Subject: [PATCH 3/5] feat: added deprecated endpoint back for backwards compatibility --- .../routes/v1/identity-token-auth-router.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/backend/src/server/routes/v1/identity-token-auth-router.ts b/backend/src/server/routes/v1/identity-token-auth-router.ts index ff45778b6..77eb8768b 100644 --- a/backend/src/server/routes/v1/identity-token-auth-router.ts +++ b/backend/src/server/routes/v1/identity-token-auth-router.ts @@ -408,6 +408,60 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider } }); + // deprecated - use the GET /token-auth/tokens/:tokenId instead, this endpoint will be removed in the future + server.route({ + method: "GET", + url: "/token-auth/identities/:identityId/tokens/:tokenId", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + hide: false, + tags: [ApiDocsTags.TokenAuth], + description: "Get token for machine identity with Token Auth", + security: [ + { + bearerAuth: [] + } + ], + params: z.object({ + identityId: z.string().describe(TOKEN_AUTH.GET_TOKEN.identityId), + tokenId: z.string().describe(TOKEN_AUTH.GET_TOKEN.tokenId) + }), + response: { + 200: z.object({ + token: IdentityAccessTokensSchema + }) + } + }, + handler: async (req) => { + const { token, identityMembershipOrg } = await server.services.identityTokenAuth.getTokenAuthTokenById({ + tokenId: req.params.tokenId, + actor: req.permission.type, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + actorAuthMethod: req.permission.authMethod, + isActorSuperAdmin: isSuperAdmin(req.auth) + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: identityMembershipOrg.scopeOrgId, + event: { + type: EventType.GET_TOKEN_IDENTITY_TOKEN_AUTH, + metadata: { + identityId: token.identityId, + identityName: identityMembershipOrg.identity.name, + tokenId: token.id + } + } + }); + + return { token }; + } + }); + server.route({ method: "GET", url: "/token-auth/tokens/:tokenId", From 0ae7eac8103dd35350e73efaac0629ca92c83785 Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Tue, 2 Dec 2025 00:39:01 +0530 Subject: [PATCH 4/5] fix: added constants file --- backend/src/lib/api-docs/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 6af683c83..970f9a1a0 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -595,6 +595,7 @@ export const TOKEN_AUTH = { limit: "The number of tokens to return." }, GET_TOKEN: { + identityId: "The ID of the machine identity to get the token for.", tokenId: "The ID of the token to get metadata for." }, CREATE_TOKEN: { From 150b8fd3979b1891a0ca48e0f695151006d3153b Mon Sep 17 00:00:00 2001 From: Piyush Gupta Date: Wed, 3 Dec 2025 02:33:50 +0530 Subject: [PATCH 5/5] fix: review changes --- .../src/server/routes/v1/identity-token-auth-router.ts | 8 +++----- .../identity-token-auth/identity-token-auth-service.ts | 3 --- .../identity-token-auth/identity-token-auth-types.ts | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/backend/src/server/routes/v1/identity-token-auth-router.ts b/backend/src/server/routes/v1/identity-token-auth-router.ts index 77eb8768b..71f299e43 100644 --- a/backend/src/server/routes/v1/identity-token-auth-router.ts +++ b/backend/src/server/routes/v1/identity-token-auth-router.ts @@ -417,7 +417,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), schema: { - hide: false, + hide: true, tags: [ApiDocsTags.TokenAuth], description: "Get token for machine identity with Token Auth", security: [ @@ -441,8 +441,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId, - actorAuthMethod: req.permission.authMethod, - isActorSuperAdmin: isSuperAdmin(req.auth) + actorAuthMethod: req.permission.authMethod }); await server.services.auditLog.createAuditLog({ @@ -493,8 +492,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider actor: req.permission.type, actorId: req.permission.id, actorOrgId: req.permission.orgId, - actorAuthMethod: req.permission.authMethod, - isActorSuperAdmin: isSuperAdmin(req.auth) + actorAuthMethod: req.permission.authMethod }); await server.services.auditLog.createAuditLog({ diff --git a/backend/src/services/identity-token-auth/identity-token-auth-service.ts b/backend/src/services/identity-token-auth/identity-token-auth-service.ts index a8e129511..1a20b1192 100644 --- a/backend/src/services/identity-token-auth/identity-token-auth-service.ts +++ b/backend/src/services/identity-token-auth/identity-token-auth-service.ts @@ -621,7 +621,6 @@ export const identityTokenAuthServiceFactory = ({ const getTokenAuthTokenById = async ({ tokenId, - isActorSuperAdmin, actorId, actor, actorAuthMethod, @@ -644,8 +643,6 @@ export const identityTokenAuthServiceFactory = ({ throw new NotFoundError({ message: `Failed to find identity with ID ${foundToken.identityId}` }); } - await validateIdentityUpdateForSuperAdminPrivileges(foundToken.identityId, isActorSuperAdmin); - if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) { throw new BadRequestError({ message: "The identity does not have Token Auth" diff --git a/backend/src/services/identity-token-auth/identity-token-auth-types.ts b/backend/src/services/identity-token-auth/identity-token-auth-types.ts index 4e7f2a499..6be2c5fe0 100644 --- a/backend/src/services/identity-token-auth/identity-token-auth-types.ts +++ b/backend/src/services/identity-token-auth/identity-token-auth-types.ts @@ -42,7 +42,6 @@ export type TGetTokenAuthTokensDTO = { export type TGetTokenAuthTokenByIdDTO = { tokenId: string; - isActorSuperAdmin?: boolean; } & Omit; export type TUpdateTokenAuthTokenDTO = {