JWT Security Review Checklist for Web APIs
Token profile, key boundary, and rejection tests
Define a token profile for every use: allowed algorithm, trusted issuer, key set, audience, required claims, token type, and clock tolerance. RFC 8725 requires callers to configure accepted algorithms rather than follow untrusted alg. kid chooses inside a configured key set; it must not select an arbitrary file, SQL record, LDAP value, jku, or x5u URL.
Create rejection tests for none, algorithm swap, unknown key ID, signature corruption, expired token, not-yet-valid token, wrong issuer, wrong audience, wrong type, and valid token from another application. A payment access token should fail administration API even when cryptography passes. Nested signed-and-encrypted tokens require validation of every operation. Keep decoded test headers redacted, verifier configuration version, key-rotation timeline, and clock-boundary output.
Repair uses maintained library calls with explicit algorithm and claim options, separate verifier instances per issuer or token purpose, and bounded key overlap during rotation. Closure proves old key behavior follows rotation plan and wrong-audience token stays denied. Authorization still follows verification: a valid subject claim does not grant an unlisted action. Any compatibility exception must name legacy issuer, end date, and restricted audience.
Clock handling needs explicit test data. Verify expiry at boundary, accepted skew, and rejection after it; do not silently rely on system default. Key rotation test should show new key acceptance and retired-key behavior without querying untrusted locations. If claims select database records or permissions, treat them as validated input still subject to local authorization. A compact JWT can be signed yet contain excessive or inappropriate claims; profile must reject it.
Define a verifier profile
A JWT signature alone is not authorization. Define one verifier profile for each token use: permitted algorithm, issuer, trusted key source, expected audience, token type, required claims, allowed clock skew, and local authorization policy. RFC 8725 says applications must specify accepted algorithms and reject others. Do not let untrusted alg choose behavior, and do not let kid, jku, or x5u become a file name, database selector, or arbitrary URL fetch.
Build a worked rejection suite. Start with a valid token for payment API, then try it at administration API. Next alter alg, replace key ID, corrupt signature, remove audience, substitute issuer, cross token type, set expired exp, future nbf, malformed time claim, and oversized header. Expected result is failure before subject lookup, policy check, database query, or provider call. A token with a familiar audience substring is not enough; match intended service identifier exactly, including array handling rules.
Key selection and rotation
Obtain issuer metadata and JWK set only from configured trusted HTTPS locations. Cache behavior should distinguish a known retired key from a never-seen key. During planned rotation, test new-key acceptance, valid old-key overlap, and old-key rejection after retirement. During compromise response, remove the affected key and confirm caches converge to rejection. Keep key-set version, cache interval, verifier configuration, and redacted header tests as evidence. Nested tokens require validating each cryptographic layer according to profile.
Claims, replay, and local policy
Validate claim types as well as values. iss must bind to key ownership; aud must name this recipient; sub must represent an allowed issuer-subject pair. Apply explicit type or mutually exclusive validation rules when ID tokens, access tokens, and security-event tokens can share an issuer. Token validation provides context; a separate local policy still decides whether subject may approve a refund or read an object.
JWTs do not by themselves give immediate revocation. For sensitive sessions, combine short token lifetime with server-side session or revocation policy. Test a token after logout, permission removal, and key retirement. Remediate with maintained library calls that pin algorithm and claims, distinct profiles per purpose, bounded key overlap, and rejection metrics. An issuer migration exception identifies exact issuer, audience, end date, and test output. Closure reruns algorithm-confusion, wrong-audience, and rotation tests after deployment.
Rejection telemetry
Classify rejection without returning claim details to caller: algorithm mismatch, key unknown, signature failure, issuer mismatch, audience mismatch, type mismatch, and expired token. Metrics expose configuration drift while preserving token secrecy. A sudden audience-mismatch increase after deployment can identify a client using wrong resource server. Investigate with correlation identifiers and configuration revision, not copied bearer values. This signal also confirms verifiers use intended profile rather than a permissive fallback.
JWT verifier review artifact
| Token check | Identity owner | Verification status | JWT evidence | Expected verifier result | Observed verifier result | Token exception | Verification closure |
|---|---|---|---|---|---|---|---|
JWT-ROT-03 retired signing key | identity platform owner | Open | verifier config v42, redacted kid test, rotation log | new key accepted; retired key denied after overlap | retired key still accepted by one cache node | EX-17, cache overlap until 2026-06-20, security owner approved | purge cache, rerun retired-key and wrong-audience tests, attach request IDs |