Context
Currently, jwtVerify(token, JWKS) in both protocol/src/guards/auth.guard.ts (Line 30) and protocol/src/controllers/mcp.handler.ts (Lines 88–100) validates signature and expiration only — it does not validate the iss (issuer) or aud (audience) claims.
Better Auth's JWT plugin (protocol/src/lib/betterauth/betterauth.ts) currently embeds issuer: BASE_URL when issuing tokens but does not embed an aud claim. This means:
- Any cryptographically valid JWT from the same JWKS with a string
id or sub claim can authenticate to any endpoint, regardless of intended scope.
- Adding
audience validation unilaterally would immediately reject all existing tokens (since no aud is embedded today).
Required coordinated change
This fix must be done atomically across three files to avoid breaking existing tokens:
protocol/src/lib/betterauth/betterauth.ts — Add an audience claim (e.g., BASE_URL or a service-specific string) to the JWT plugin's definePayload or JWT config.
protocol/src/guards/auth.guard.ts — Update jwtVerify(token, JWKS) to jwtVerify(token, JWKS, { issuer: BASE_URL, audience: '<agreed_value>' }).
protocol/src/controllers/mcp.handler.ts — Same update to the jwtVerify call in authResolver.resolveUserId.
References
Context
Currently,
jwtVerify(token, JWKS)in bothprotocol/src/guards/auth.guard.ts(Line 30) andprotocol/src/controllers/mcp.handler.ts(Lines 88–100) validates signature and expiration only — it does not validate theiss(issuer) oraud(audience) claims.Better Auth's JWT plugin (
protocol/src/lib/betterauth/betterauth.ts) currently embedsissuer: BASE_URLwhen issuing tokens but does not embed anaudclaim. This means:idorsubclaim can authenticate to any endpoint, regardless of intended scope.audiencevalidation unilaterally would immediately reject all existing tokens (since noaudis embedded today).Required coordinated change
This fix must be done atomically across three files to avoid breaking existing tokens:
protocol/src/lib/betterauth/betterauth.ts— Add anaudienceclaim (e.g.,BASE_URLor a service-specific string) to the JWT plugin'sdefinePayloador JWT config.protocol/src/guards/auth.guard.ts— UpdatejwtVerify(token, JWKS)tojwtVerify(token, JWKS, { issuer: BASE_URL, audience: '<agreed_value>' }).protocol/src/controllers/mcp.handler.ts— Same update to thejwtVerifycall inauthResolver.resolveUserId.References