feat: Add optional WORKOS_ISSUER access token issuer validation - #476
feat: Add optional WORKOS_ISSUER access token issuer validation#476m0tzy wants to merge 2 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
Original prompt from madison.packer
|
Greptile SummaryAdds optional access-token issuer validation configured through
Confidence Score: 3/5The PR is not yet safe to merge because malformed nonempty issuer configuration silently disables the new authentication constraint. An all-empty parsed issuer list becomes Files Needing Attention: src/session.ts
|
| Filename | Overview |
|---|---|
| src/session.ts | Adds issuer-list parsing and passes the result to JWT verification, but an empty parsed list silently disables the constraint. |
| src/env-variables.ts | Exposes the optional WORKOS_ISSUER process-level configuration value. |
| src/session.spec.ts | Covers unset, single, and comma-separated issuer options but not malformed all-empty input. |
| README.md | Documents the optional single or comma-separated issuer configuration. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
E[WORKOS_ISSUER] --> P[Split, trim, and remove empty entries]
P --> C{Parsed issuers exist?}
C -->|Yes| V[jwtVerify with expected issuer]
C -->|No| U[jwtVerify without issuer validation]
V --> R[Accept only matching issuer]
U --> F[Fail-open configuration path]
Prompt To Fix All With AI
### Issue 1
src/session.ts:611
**Malformed issuer disables validation**
If `WORKOS_ISSUER` contains only whitespace or delimiters, such as `","`, parsing produces an empty list and returns `undefined`. `verifyAccessToken` then omits the issuer option, so otherwise-valid tokens are accepted without the configured issuer constraint. Malformed security configuration should reject the token rather than silently disabling validation.
**How this was verified:** The raw environment value reaches this parser without validation, and an empty parsed list causes `jwtVerify` to receive no expected issuer.
```suggestion
if (issuers.length === 0) {
throw new Error('WORKOS_ISSUER must contain at least one issuer');
}
return issuers.length === 1 ? issuers[0] : issuers;
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (2): Last reviewed commit: "Accept a comma-separated list of issuers..." | Re-trigger Greptile
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Summary
Adds an opt-in
issclaim check to access token verification. WhenWORKOS_ISSUERis set, it is passed tojose.jwtVerifyas the expected issuer; when unset, behavior is unchanged (signature + expiry only, noisscheck).WORKOS_ISSUERmay be a single issuer or a comma-separated list;getExpectedIssuer()splits on commas (trimmed, empties dropped) and forwards a plain string for one value or astring[]for several —jose'sissueroption accepts both.Opt-in rather than defaulted because the API does not mint a single issuer shape — it varies by environment (
https://api.workos.comfor legacy environments,https://api.workos.com/user_management/<clientId>for environments created since mid-2025, custom auth domains, and flag-gated/sso/<clientId>and/convex/<clientId>variants). A hardcoded default would reject valid tokens and force a refresh on every request for most environments. The list form covers apps that accept tokens from more than one of those issuers (e.g. during an issuer migration). Same shape as theissueroverride in workos/authkit-react-router#85.Link to Devin session: https://app.devin.ai/sessions/0ee38e859a9849658a7cdb2d215d89a6
Open in Devin Desktop: https://app.devin.ai/desktop/session/0ee38e859a9849658a7cdb2d215d89a6?variant=devin
Requested by: @m0tzy