From 9dd95a372be69a329d711c5f2033bfecc5d89df2 Mon Sep 17 00:00:00 2001 From: Iain Sproat <68657+iainsproat@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:23:07 +0100 Subject: [PATCH] chore(server): include token id in auth context (#5025) - it is relevant to understand which token was used to act on behalf of an user --- packages/server/modules/core/helpers/types.ts | 10 ++++++++++ packages/server/modules/core/services/tokens.ts | 9 +++++---- packages/server/modules/shared/domain/authz/types.ts | 1 + packages/server/modules/shared/middleware/index.ts | 4 +++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/packages/server/modules/core/helpers/types.ts b/packages/server/modules/core/helpers/types.ts index 70eac36d5..9438093fe 100644 --- a/packages/server/modules/core/helpers/types.ts +++ b/packages/server/modules/core/helpers/types.ts @@ -147,12 +147,22 @@ export type ObjectRecord = { export type InvalidTokenResult = { valid: false + /** + * The ID of the token used for validation. + * This is the first 10 characters of the token string. + */ + tokenId: string } export type ValidTokenResult = { valid: true scopes: string[] userId: string + /** + * The ID of the token used for validation. + * This is the first 10 characters of the token string. + */ + tokenId: string role: ServerRoles /** * Set, if the token is an app token diff --git a/packages/server/modules/core/services/tokens.ts b/packages/server/modules/core/services/tokens.ts index 720bb7775..a883c66ff 100644 --- a/packages/server/modules/core/services/tokens.ts +++ b/packages/server/modules/core/services/tokens.ts @@ -141,13 +141,13 @@ export const validateTokenFactory = const token = await deps.getApiTokenById(tokenId) if (!token) { - return { valid: false } + return { valid: false, tokenId } } const timeDiff = Math.abs(Date.now() - new Date(token.createdAt).getTime()) if (timeDiff > token.lifespan) { await deps.revokeUserTokenById(tokenId, token.owner) - return { valid: false } + return { valid: false, tokenId } } const valid = await bcrypt.compare(tokenContent, token.tokenDigest) @@ -167,7 +167,8 @@ export const validateTokenFactory = role: role!, scopes: scopes.map((s) => s.scopeName), appId: app?.id || null, - resourceAccessRules: resourceAccessRules.length ? resourceAccessRules : null + resourceAccessRules: resourceAccessRules.length ? resourceAccessRules : null, + tokenId } - } else return { valid: false } + } else return { valid: false, tokenId } } diff --git a/packages/server/modules/shared/domain/authz/types.ts b/packages/server/modules/shared/domain/authz/types.ts index 9ca8a4700..a5d156885 100644 --- a/packages/server/modules/shared/domain/authz/types.ts +++ b/packages/server/modules/shared/domain/authz/types.ts @@ -7,6 +7,7 @@ export interface AuthContext { auth: boolean userId?: string role?: ServerRoles + tokenId?: string token?: string scopes?: string[] stream?: StreamWithOptionalRole diff --git a/packages/server/modules/shared/middleware/index.ts b/packages/server/modules/shared/middleware/index.ts index fc863a45f..eeb4b5587 100644 --- a/packages/server/modules/shared/middleware/index.ts +++ b/packages/server/modules/shared/middleware/index.ts @@ -106,13 +106,15 @@ export async function createAuthContextFromToken( if (!tokenValidationResult.valid) return { auth: false, err: new ForbiddenError('Your token is not valid.') } - const { scopes, userId, role, appId, resourceAccessRules } = tokenValidationResult + const { scopes, userId, tokenId, role, appId, resourceAccessRules } = + tokenValidationResult return { auth: true, userId, role, token, + tokenId, scopes, appId, resourceAccessRules: resourceAccessRules