The /api JWT branch reused the MCP /oauth2 verification (AuthKit /oauth2/jwks, issuer + audience pinned), but a device-login token is a WorkOS user_management access token: signed by the SSO keyset (<workos-api>/sso/jwks/<clientId>), with no audience and an app-specific issuer. So real-WorkOS device tokens 401'd on /api (key not in the oauth2 JWKS) while login + whoami worked. Verify the user_management token against the client-scoped SSO JWKS by signature + expiry only (no issuer/audience pin); live org-membership is still re-checked. Caught by a real executor.sh login; the e2e missed it because the emulator signed all tokens with one keypair (fixed in the emulate fork to split the keysets).
Showing the changes to apps/cloud/src/api (1 of 4 files). Show all
Unified · Split
| @@ -19,7 +19,9 @@ const makeJwt = async () => { · 18 unmodified lines | ||
| 19 | 19 | const { publicKey, privateKey } = await generateKeyPair("RS256"); |
| 20 | 20 | const jwk = await exportJWK(publicKey); |
| 21 | 21 | const jwks = createLocalJWKSet({ keys: [{ ...jwk, kid: "test-key" }] }); |
| 22 | − const config: JwtBearerConfig = { jwks, issuer, audience }; | |
| 22 | + // Device-login tokens are verified by signature alone (client-scoped SSO | |
| 23 | + // JWKS); issuer/audience are not pinned. | |
| 24 | + const config: JwtBearerConfig = { jwks }; | |
| 23 | 25 | const sign = (claims: Record<string, unknown>, expiration: string | number = "5m") => |
| 24 | 26 | new SignJWT(claims) |
| 25 | 27 | .setProtectedHeader({ alg: "RS256", kid: "test-key" }) |