Merge pull request #4966 from Infisical/fix/get-token-auth-token-endpoint

fix: get token auth token endpoint [ENG-4248]
This commit is contained in:
Piyush Gupta
2025-12-03 11:41:18 +05:30
committed by GitHub
5 changed files with 94 additions and 27 deletions

View File

@@ -408,6 +408,7 @@ 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({ server.route({
method: "GET", method: "GET",
url: "/token-auth/identities/:identityId/tokens/:tokenId", url: "/token-auth/identities/:identityId/tokens/:tokenId",
@@ -416,7 +417,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
schema: { schema: {
hide: false, hide: true,
tags: [ApiDocsTags.TokenAuth], tags: [ApiDocsTags.TokenAuth],
description: "Get token for machine identity with Token Auth", description: "Get token for machine identity with Token Auth",
security: [ security: [
@@ -436,13 +437,11 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
}, },
handler: async (req) => { handler: async (req) => {
const { token, identityMembershipOrg } = await server.services.identityTokenAuth.getTokenAuthTokenById({ const { token, identityMembershipOrg } = await server.services.identityTokenAuth.getTokenAuthTokenById({
identityId: req.params.identityId,
tokenId: req.params.tokenId, tokenId: req.params.tokenId,
actor: req.permission.type, actor: req.permission.type,
actorId: req.permission.id, actorId: req.permission.id,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod
isActorSuperAdmin: isSuperAdmin(req.auth)
}); });
await server.services.auditLog.createAuditLog({ await server.services.auditLog.createAuditLog({
@@ -462,6 +461,57 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
} }
}); });
server.route({
method: "GET",
url: "/token-auth/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({
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
});
await server.services.auditLog.createAuditLog({
...req.auditLogInfo,
orgId: identityMembershipOrg.scopeOrgId,
event: {
type: EventType.GET_TOKEN_IDENTITY_TOKEN_AUTH,
metadata: {
identityId: identityMembershipOrg.identity.id,
identityName: identityMembershipOrg.identity.name,
tokenId: token.id
}
}
});
return { token };
}
});
server.route({ server.route({
method: "PATCH", method: "PATCH",
url: "/token-auth/tokens/:tokenId", url: "/token-auth/tokens/:tokenId",

View File

@@ -621,29 +621,49 @@ export const identityTokenAuthServiceFactory = ({
const getTokenAuthTokenById = async ({ const getTokenAuthTokenById = async ({
tokenId, tokenId,
identityId,
isActorSuperAdmin,
actorId, actorId,
actor, actor,
actorAuthMethod, actorAuthMethod,
actorOrgId actorOrgId
}: TGetTokenAuthTokenByIdDTO) => { }: 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({ const identityMembershipOrg = await membershipIdentityDAL.getIdentityById({
scopeData: { scopeData: {
scope: AccessScope.Organization, scope: AccessScope.Organization,
orgId: actorOrgId 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}` });
}
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) { if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
throw new BadRequestError({ throw new BadRequestError({
message: "The identity does not have Token Auth" message: "The identity does not have Token Auth"
}); });
} }
if (identityMembershipOrg.identity.projectId) {
const { permission } = await permissionService.getProjectPermission({
actionProjectType: ActionProjectType.Any,
actor,
actorId,
projectId: identityMembershipOrg.identity.projectId,
actorAuthMethod,
actorOrgId
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionIdentityActions.Read,
subject(ProjectPermissionSub.Identity, { identityId: identityMembershipOrg.identity.id })
);
} else {
const { permission } = await permissionService.getOrgPermission({ const { permission } = await permissionService.getOrgPermission({
scope: OrganizationActionScope.Any, scope: OrganizationActionScope.Any,
actor, actor,
@@ -653,16 +673,9 @@ export const identityTokenAuthServiceFactory = ({
actorOrgId actorOrgId
}); });
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
}
const token = await identityAccessTokenDAL.findOne({ return { token: foundToken, identityMembershipOrg };
[`${TableName.IdentityAccessToken}.id` as "id"]: tokenId,
[`${TableName.IdentityAccessToken}.authMethod` as "authMethod"]: IdentityAuthMethod.TOKEN_AUTH,
[`${TableName.IdentityAccessToken}.identityId` as "identityId"]: identityId
});
if (!token) throw new NotFoundError({ message: `Token with ID ${tokenId} not found` });
return { token, identityMembershipOrg };
}; };
const updateTokenAuthToken = async ({ const updateTokenAuthToken = async ({

View File

@@ -42,8 +42,6 @@ export type TGetTokenAuthTokensDTO = {
export type TGetTokenAuthTokenByIdDTO = { export type TGetTokenAuthTokenByIdDTO = {
tokenId: string; tokenId: string;
identityId: string;
isActorSuperAdmin?: boolean;
} & Omit<TProjectPermission, "projectId">; } & Omit<TProjectPermission, "projectId">;
export type TUpdateTokenAuthTokenDTO = { export type TUpdateTokenAuthTokenDTO = {

View File

@@ -0,0 +1,4 @@
---
title: "Get Token"
openapi: "GET /api/v1/auth/token-auth/tokens/{tokenId}"
---

View File

@@ -22,6 +22,7 @@ import {
Tooltip, Tooltip,
Tr Tr
} from "@app/components/v2"; } from "@app/components/v2";
import { CopyButton } from "@app/components/v2/CopyButton";
import { import {
OrgPermissionIdentityActions, OrgPermissionIdentityActions,
OrgPermissionSubjects, OrgPermissionSubjects,
@@ -153,6 +154,7 @@ export const IdentityTokenAuthTokensTable = ({ tokens, identityId }: Props) => {
</Td> </Td>
<Td> <Td>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<CopyButton value={id} size="xs" variant="plain" name="Token ID" />
<VariablePermissionCan <VariablePermissionCan
type={projectId ? "project" : "org"} type={projectId ? "project" : "org"}
I={ I={