Repository navigation
feat(user-management): Add verifyAccessToken - #1733
gjtorikian wants to merge 1 commit into
Conversation
The SDK already verified access tokens against the environment's JWKS inside `authenticateWithSessionCookie`, but only through a private helper, so applications that receive an access token outside a sealed session cookie (for example from an `Authorization: Bearer` header) had to wire up jose and the JWKS URL themselves. Expose `userManagement.verifyAccessToken(accessToken)`. It checks the signature, expiry and, when configured, the issuer, and resolves to the token's claims typed as `AccessTokenClaims`, or `null` when the token is invalid. Non-JWT errors such as a failed JWKS fetch still propagate, the same contract the session helpers use. `isValidJwt` now delegates to it, and the method is part of the public-client surface since it needs only a client ID. Fixes #1315
[Medium impact] The change reaches applications that verify WorkOS access tokens through the User Management SDK. The PR appears safe to merge, with non-blocking improvements to required-claim checks and the README example. FindingsFix with agent prompt### Issue 1
src/user-management/user-management.ts:771-776
`verifyAccessToken` returns the payload as `AccessTokenClaims` without checking that `sub`, `sid`, `iss`, `exp`, and `iat` exist. The type argument does not check these fields at runtime. If a signed token for another purpose lacks them, callers receive missing values where TypeScript promises values.
Add a required-claims check before returning, as `hasRequiredAgentClaims` already does for agent tokens.
### Issue 2
README.md:95-97
The example continues to `claims.sub` after `verifyAccessToken` returns `null`. The comment inside `if (!claims)` does not stop execution, so the pasted example fails TypeScript's null check and throws for an invalid token. Use a `throw` or `return` in that branch.
```suggestion
if (!claims) {
throw new Error('Invalid access token');
}
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.SummaryAdds public
|
| const { payload } = await jwtVerify<AccessTokenClaims>( | ||
| accessToken, | ||
| jwks, | ||
| this.issuer ? { issuer: this.issuer } : undefined, | ||
| ); | ||
| return true; | ||
| return payload; |
There was a problem hiding this comment.
verifyAccessToken returns the payload as AccessTokenClaims without checking that sub, sid, iss, exp, and iat exist. The type argument does not check these fields at runtime. If a signed token for another purpose lacks them, callers receive missing values where TypeScript promises values.
Add a required-claims check before returning, as hasRequiredAgentClaims already does for agent tokens.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/user-management/user-management.ts
Line: 771-776
Comment:
**Required claims go unchecked**
`verifyAccessToken` returns the payload as `AccessTokenClaims` without checking that `sub`, `sid`, `iss`, `exp`, and `iat` exist. The type argument does not check these fields at runtime. If a signed token for another purpose lacks them, callers receive missing values where TypeScript promises values.
Add a required-claims check before returning, as `hasRequiredAgentClaims` already does for agent tokens.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| if (!claims) { | ||
| // Reject the request. | ||
| } |
There was a problem hiding this comment.
The example continues to claims.sub after verifyAccessToken returns null. The comment inside if (!claims) does not stop execution, so the pasted example fails TypeScript's null check and throws for an invalid token. Use a throw or return in that branch.
| if (!claims) { | |
| // Reject the request. | |
| } | |
| if (!claims) { | |
| throw new Error('Invalid access token'); | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: README.md
Line: 95-97
Comment:
**Example reads rejected claims**
The example continues to `claims.sub` after `verifyAccessToken` returns `null`. The comment inside `if (!claims)` does not stop execution, so the pasted example fails TypeScript's null check and throws for an invalid token. Use a `throw` or `return` in that branch.
```suggestion
if (!claims) {
throw new Error('Invalid access token');
}
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Description
The SDK already verifies access tokens against the environment's JWKS inside
authenticateWithSessionCookie, but only via the privateisValidJwt. Applications that receive an access token outside a sealed session cookie, for example from anAuthorization: Bearerheader on an API route, had to wire upjose,getJwksUrl()and the issuer check themselves.This adds a public
userManagement.verifyAccessToken(accessToken):AccessTokenClaims(sub,iss,exp,iat,auth_time, plus the existingUserManagementAccessTokensession claims and an index signature for custom claims).nullwhen the token is invalid; errors that are not JWT validation failures, such as a network error fetching the JWKS, propagate. Throws when no client ID was configured.isValidJwtnow delegates to it, so the session helpers keep their behavior.PublicUserManagementMethods, since verification needs only a client ID.The README gains a short "Verifying access tokens" section next to the issuer validation notes.
Fixes #1315
Documentation
Does this require changes to the WorkOS Docs? E.g. the API Reference or code snippets need updates.
If yes, link a related docs PR and add a docs maintainer as a reviewer. Their approval is required.