diff --git a/packages/services/agent-service/src/interfaces/rest/controllers/agent.controller.ts b/packages/services/agent-service/src/interfaces/rest/controllers/agent.controller.ts index 5810584..473dba2 100644 --- a/packages/services/agent-service/src/interfaces/rest/controllers/agent.controller.ts +++ b/packages/services/agent-service/src/interfaces/rest/controllers/agent.controller.ts @@ -139,9 +139,11 @@ export class AgentController { this.logger.log(`[Task ${task.id}] Resuming SDK session: ${resumeSessionId}`); } - // Build system prompt with user context so iAgent knows who it's serving - const userId: string | undefined = req.user?.sub ?? req.user?.userId; - const userEmail: string | undefined = req.user?.email; + // Build system prompt with user context so iAgent knows who it's serving. + // Kong already verifies the JWT — just decode the payload (no signature check needed). + const jwtPayload = this.decodeJwt(req.headers?.['authorization'] as string | undefined); + const userId: string | undefined = jwtPayload?.sub ?? req.user?.sub ?? req.user?.userId; + const userEmail: string | undefined = jwtPayload?.email ?? req.user?.email; const systemPrompt = body.systemPrompt || this.systemPromptBuilder.build({ tenantId, userId, @@ -788,6 +790,17 @@ export class AgentController { }); } + /** Decode JWT payload without verifying signature (Kong already verified it). */ + private decodeJwt(authHeader: string | undefined): Record | null { + if (!authHeader?.startsWith('Bearer ')) return null; + try { + const payload = authHeader.slice(7).split('.')[1]; + return JSON.parse(Buffer.from(payload, 'base64url').toString('utf8')); + } catch { + return null; + } + } + private createNewSession( tenantId: string, engineType: string, diff --git a/packages/services/agent-service/src/interfaces/rest/controllers/voice-session.controller.ts b/packages/services/agent-service/src/interfaces/rest/controllers/voice-session.controller.ts index efcdaf9..e2ee1f7 100644 --- a/packages/services/agent-service/src/interfaces/rest/controllers/voice-session.controller.ts +++ b/packages/services/agent-service/src/interfaces/rest/controllers/voice-session.controller.ts @@ -82,10 +82,11 @@ export class VoiceSessionController { // so Claude can call the DingTalk OAuth trigger endpoint with the correct session. const sessionId = session?.id ?? crypto.randomUUID(); - // Extract user identity from JWT for context-aware system prompt + // Extract user identity — decode JWT directly (Kong already verified the signature). + const jwtPayload = this.decodeJwt((req as any).headers?.['authorization']); const jwtUser = (req as any).user; - const userId: string | undefined = jwtUser?.sub ?? jwtUser?.userId; - const userEmail: string | undefined = jwtUser?.email; + const userId: string | undefined = jwtPayload?.sub ?? jwtUser?.sub ?? jwtUser?.userId; + const userEmail: string | undefined = jwtPayload?.email ?? jwtUser?.email; // Build the full iAgent system prompt (includes DingTalk binding instructions, userId, etc.) // If the caller explicitly overrides with their own systemPrompt, use that instead. @@ -306,4 +307,15 @@ export class VoiceSessionController { return { triggered: true, instanceId: body.instanceId, instanceName }; } + + /** Decode JWT payload without verifying signature (Kong already verified it). */ + private decodeJwt(authHeader: string | undefined): Record | null { + if (!authHeader?.startsWith('Bearer ')) return null; + try { + const payload = authHeader.slice(7).split('.')[1]; + return JSON.parse(Buffer.from(payload, 'base64url').toString('utf8')); + } catch { + return null; + } + } }