From 65c7d09584c5674d83a9428d907b6426e80906c9 Mon Sep 17 00:00:00 2001 From: Saravanakumar Dhandapani Date: Sun, 31 May 2026 04:00:03 -0700 Subject: [PATCH] feat(auth): include displayName claim in platform access token Adds an optional displayName claim to the platform access token so downstream product backends can source the user's display name from the JWT (single source of truth = platform auth), not from per-product DB copies. verifyToken already exposes displayName; this populates it at all token-minting sites (password login, register, refresh, SSO, OAuth, magic-link, passkeys, QR, enterprise SAML/OIDC). Additive and backward compatible. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../platform-service/src/modules/auth/enterprise/routes.ts | 2 ++ services/platform-service/src/modules/auth/jwt.ts | 3 +++ .../platform-service/src/modules/auth/magic-link/routes.ts | 1 + services/platform-service/src/modules/auth/oauth/routes.ts | 1 + services/platform-service/src/modules/auth/passkeys/routes.ts | 1 + services/platform-service/src/modules/auth/qr-auth/routes.ts | 1 + services/platform-service/src/modules/auth/routes.ts | 4 ++++ 7 files changed, 13 insertions(+) diff --git a/services/platform-service/src/modules/auth/enterprise/routes.ts b/services/platform-service/src/modules/auth/enterprise/routes.ts index 961d27ed..7a46853b 100644 --- a/services/platform-service/src/modules/auth/enterprise/routes.ts +++ b/services/platform-service/src/modules/auth/enterprise/routes.ts @@ -223,6 +223,7 @@ export async function enterpriseRoutes(app: FastifyInstance) { role: user.role as string, productId: idp.productId, plan: (user.plan ?? 'free') as 'free' | 'pro' | 'enterprise', + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, @@ -332,6 +333,7 @@ export async function enterpriseRoutes(app: FastifyInstance) { role: user.role as string, productId: idp.productId, plan: (user.plan ?? 'free') as 'free' | 'pro' | 'enterprise', + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, diff --git a/services/platform-service/src/modules/auth/jwt.ts b/services/platform-service/src/modules/auth/jwt.ts index ceeca2a8..8f12d164 100644 --- a/services/platform-service/src/modules/auth/jwt.ts +++ b/services/platform-service/src/modules/auth/jwt.ts @@ -17,6 +17,7 @@ export async function createAccessToken(payload: { role: string; productId: string; plan?: 'free' | 'pro' | 'enterprise'; + displayName?: string; }): Promise { return new SignJWT({ ...payload, type: 'access' }) .setProtectedHeader({ alg: 'HS256' }) @@ -44,6 +45,7 @@ export async function verifyToken(token: string): Promise<{ role?: string; productId?: string; plan?: 'free' | 'pro' | 'enterprise'; + displayName?: string; type?: string; }> { const { payload } = await jwtVerify(token, getSecret(), { @@ -55,6 +57,7 @@ export async function verifyToken(token: string): Promise<{ role?: string; productId?: string; plan?: 'free' | 'pro' | 'enterprise'; + displayName?: string; type?: string; }; } diff --git a/services/platform-service/src/modules/auth/magic-link/routes.ts b/services/platform-service/src/modules/auth/magic-link/routes.ts index 355f0f73..3ee3340b 100644 --- a/services/platform-service/src/modules/auth/magic-link/routes.ts +++ b/services/platform-service/src/modules/auth/magic-link/routes.ts @@ -121,6 +121,7 @@ export async function magicLinkRoutes(app: FastifyInstance) { role: user.role as string, productId: user.productId, plan: (user.plan ?? 'free') as 'free' | 'pro' | 'enterprise', + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, diff --git a/services/platform-service/src/modules/auth/oauth/routes.ts b/services/platform-service/src/modules/auth/oauth/routes.ts index cfe2018a..a0d825f2 100644 --- a/services/platform-service/src/modules/auth/oauth/routes.ts +++ b/services/platform-service/src/modules/auth/oauth/routes.ts @@ -175,6 +175,7 @@ export async function oauthRoutes(app: FastifyInstance) { role: user.role, productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, productId }); diff --git a/services/platform-service/src/modules/auth/passkeys/routes.ts b/services/platform-service/src/modules/auth/passkeys/routes.ts index 6b02b673..8c1c3999 100644 --- a/services/platform-service/src/modules/auth/passkeys/routes.ts +++ b/services/platform-service/src/modules/auth/passkeys/routes.ts @@ -247,6 +247,7 @@ export async function passkeyRoutes(app: FastifyInstance) { role: user.role, productId: body.productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, productId: body.productId }); diff --git a/services/platform-service/src/modules/auth/qr-auth/routes.ts b/services/platform-service/src/modules/auth/qr-auth/routes.ts index 569ad158..559e38c8 100644 --- a/services/platform-service/src/modules/auth/qr-auth/routes.ts +++ b/services/platform-service/src/modules/auth/qr-auth/routes.ts @@ -70,6 +70,7 @@ export async function qrAuthRoutes(app: FastifyInstance) { role: user.role as 'user' | 'admin' | 'super_admin', productId: challenge.productId, plan: (user.plan ?? 'free') as 'free' | 'pro' | 'enterprise', + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, diff --git a/services/platform-service/src/modules/auth/routes.ts b/services/platform-service/src/modules/auth/routes.ts index 77a1eb0e..a0e0bd1d 100644 --- a/services/platform-service/src/modules/auth/routes.ts +++ b/services/platform-service/src/modules/auth/routes.ts @@ -272,6 +272,7 @@ export async function authRoutes(app: FastifyInstance) { role: user.role, productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, productId }); @@ -380,6 +381,7 @@ export async function authRoutes(app: FastifyInstance) { role: user.role, productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, productId }); @@ -464,6 +466,7 @@ export async function authRoutes(app: FastifyInstance) { role: user.role, productId: user.productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, @@ -679,6 +682,7 @@ export async function authRoutes(app: FastifyInstance) { role: user.role, productId, plan: user.plan, + displayName: user.displayName, }); const refreshToken = await jwt.createRefreshToken({ sub: user.id, productId });