Last reviewed: 2026-10-28
Direct answer
JWT verification in coding-agent API patches needs an explicit acceptance policy. Use a maintained verification library, configure trusted algorithms and issuer keys, require the intended issuer and audience, enforce the token profile’s required claims and time rules, and reject tokens issued for another purpose. Create an authenticated principal only after every check succeeds. Decoding a token’s JSON payload establishes none of those facts.
RFC 8725 requires application-controlled algorithm restrictions, issuer-to-key binding, and validation rules that prevent different token kinds from being confused. OWASP’s REST Security Cheat Sheet recommends requiring and validating issuer, audience, and expiration for API access tokens by default. A passing signature check alone leaves those acceptance decisions unresolved.
For example, an agent adds authentication middleware that verifies a signature and copies sub into the request context. Normal requests work, but a correctly signed token intended for a different API may also work if audience validation is missing. Review the verifier’s configuration and the caller that consumes its result, then prove rejection through the real request path.
Who this is for
Use this guide when reviewing agent-written bearer-token middleware, JWT library upgrades, identity-provider integrations, or refactors that move authentication between a gateway and an application. Search for decode-only helpers, disabled verification options, permissive algorithm lists, and handlers that consume claims before verification finishes.
The running example accepts compact, digitally signed JWT access tokens from one configured issuer. It does not implement a complete OAuth or OpenID Connect flow. Encrypted or nested tokens need their own reviewed profile; this example rejects unsupported token forms rather than trying another decoder.
Key takeaways
- Write the accepted token profile before reviewing a helper named
verify. - Select allowed algorithms, trusted issuer configuration, and key sources outside the incoming token.
- Check claim presence as well as claim values. An expiry check that runs only when
expexists does not require expiration. - Bind a subject to its verified issuer; the same subject string can identify different accounts under different issuers.
- Reject a validly signed token intended for another audience or purpose.
- Assert that rejected tokens create no principal and trigger no protected handler or business effect.
- Keep object and operation authorization after authentication.
Sources checked
Three primary public pages were fetched successfully on 2026-10-28:
- IETF: RFC 8725, JSON Web Token Best Current Practices , published February 2020. Sections 3.1, 3.8–3.12 support algorithm restrictions, issuer-key binding, subject and audience validation, safe key lookup, and separation of token purposes.
- IETF: RFC 7519, JSON Web Token (JWT) , published May 2015. Sections 2 and 4.1 define NumericDate, issuer, subject, audience, expiration, and not-before semantics. Its base format leaves these registered claims optional; an application’s token profile can require them.
- OWASP: REST Security Cheat Sheet , a maintained reference whose JWT section supports integrity protection, configuration-controlled algorithms, required API-token claim checks, and session invalidation considerations. Its HTTP representation reported an October 28 modification time; that does not establish a new security announcement.
These references support an evergreen patch-review task. The example profile, verification sequence, error categories, and acceptance tests below are engineering recommendations. No application test, deployment, or vulnerability discovery is claimed. Check the selected library’s current documentation and security notices before implementing its options.
Contract details to verify
Define one accepted token profile
Write the producer-consumer agreement with the identity owner. The example API accepts signed access tokens from Issuer A for the document service. It requires iss, sub, aud, and exp; nbf is optional but enforced when present. Require additional claims if the actual issuer profile does.
| Boundary | Example acceptance rule |
|---|---|
| Representation | Supported compact signed token; reject unsupported forms |
| Algorithm | Explicit configured allowlist with compatible issuer keys; reject none |
| Issuer | Exact configured Issuer A identifier, bound to its trusted verification keys |
| Audience | Document-service identifier appears as an exact audience value |
| Subject | Required nonempty string mapped to a valid subject under that issuer |
| Expiration | Required numeric exp, checked against the verifier’s clock |
| Not before | Numeric nbf when present, checked against the same clock |
| Purpose | Documented access-token profile; other token kinds must fail its validation rules |
| Failure | No authenticated principal, protected handler, or business effect |
Rejecting unsecured tokens is part of this API profile and matches OWASP’s API guidance. RFC 8725 discusses other contexts with external cryptographic protection; that exception is not permission to accept unsigned bearer credentials here.
Keep key selection inside trusted configuration
The token’s alg describes an operation the sender requests. It cannot expand the verifier’s allowed algorithms. RFC 8725 also requires each key to be used with exactly one algorithm. Review library options and key types so an asymmetric public key cannot become a shared HMAC secret through an algorithm switch.
Treat kid as an untrusted lookup hint within the configured issuer’s key set. It must not become a filename, arbitrary database expression, or authority to import another key. Do not follow a token-supplied jku or x5u URL as an unrestricted key source. RFC 8725 identifies both unsafe key lookup and URL-driven server-side request forgery risks.
When remote key retrieval is required, configure the trusted source separately and bound its requests. Document refresh and cache validity with the identity owner. An unknown key or failed retrieval must never trigger acceptance without verification. Test that failure through the actual resolver; a mocked successful key lookup cannot prove its network policy.
For multiple issuers, select only among explicitly configured issuer profiles and still verify the final issuer-to-key binding. An unverified iss value must not authorize a new discovery URL or create trust in a new issuer.
Enforce claim presence, values, and purpose
Inspect the library’s exact behavior for missing claims. Some options validate a supplied expiration without requiring the claim. The example must reject missing exp, missing audience, or missing issuer even when the signature is valid.
RFC 7519
defines NumericDate in seconds since the Unix epoch. Do not compare it directly with a millisecond clock. Its expiration rule requires the current time to be before exp; its not-before rule permits processing at or after nbf. Configure a small documented clock tolerance if needed, and test the library’s boundary behavior. Tolerance is a deployment choice, not an automatic extension whenever a request fails.
Audience may be a single string or an array of strings. Check for the expected complete audience value using the verifier’s supported semantics. A substring match or a truthy aud field does not establish that this API is an intended recipient.
If Issuer A also issues identity tokens, make the access-token and identity-token validation rules mutually exclusive. A generic typ: JWT header does not distinguish their purposes. RFC 8725 describes stronger separation through profile-specific typing, required claims or values, distinct audiences, keys, or issuers. Choose the combination the real producer and consumer implement; do not invent a header value that the issuer never sends.
Construct identity only from the accepted result
This framework-neutral sequence shows the order of obligations:
- Load the route’s configured verification profile.
- Require exactly one bearer credential within the input-size limit.
- Verify that credential using the profile’s cryptographic and claim options.
- Enforce any remaining profile rules that the library does not check.
- Resolve the verified issuer-subject pair to a valid application principal.
- Authorize that principal for the requested action and object.
- Invoke the protected handler only after those checks succeed.
The library configuration and application checks must actually enforce the table. Complete every profile check before creating identity; a later rejection cannot repair a verifier that has already published untrusted claims as identity. Keep accepted claims separate from any object returned by a decode-only helper.
Authentication establishes the accepted identity. Use the site’s object-level authorization workflow to decide whether that principal may act on the selected record. For update routes, the mass-assignment review adds the separate question of which fields the action may change.
Happy-path operator workflow
- Freeze the proposed revision and identify every changed token parser, verifier, key resolver, middleware registration, and claims consumer.
- Write the issuer, key, algorithm, audience, time, subject, and purpose policy. Compare it with the actual identity provider’s contract.
- Inspect the installed library version and options. Require missing-claim rejection explicitly where the library needs a separate option.
- Trace the verified result into principal creation. Check middleware order and alternate routes so no handler can consume decode-only claims.
- Create disposable signing keys and synthetic accounts. Configure the test verifier with the corresponding trusted public keys.
- Exercise a valid token through the real middleware and handler. Verify the intended principal and exactly the authorized effect.
- Run the rejection matrix, attach sanitized results to the revision, and repeat affected checks after agent follow-up edits.
Prove the boundary with a token matrix
Use local fixtures and an injectable clock. Sign claim-policy failures with a trusted test key so they reach the intended check. A wrong-audience token with an invalid signature tests signature rejection instead of proving audience enforcement.
| Fixture | Required observation under the example policy |
|---|---|
| Valid Issuer A token for this API | Expected issuer-subject identity and one authorized effect |
| Payload altered after signing | Rejected; no principal or protected handler call |
| Unsigned token or disallowed algorithm | Rejected without algorithm downgrade |
Token signed by untrusted Issuer B using a colliding kid | Rejected; key IDs do not create issuer trust |
Valid signature with wrong or missing iss | Rejected by issuer/profile enforcement |
Valid signature with wrong or missing aud | Rejected; unrelated audiences cannot authorize this API |
| Audience string and array containing this API | Both accepted when the remaining profile is valid |
Missing exp, string-valued exp, or expired token | Rejected according to required-claim, type, and clock rules |
Future nbf, then the allowed boundary | Rejected before the boundary; accepted at the configured boundary |
| Validly signed identity token from the same issuer | Rejected by the access-token profile |
| Missing or unmapped subject | No accepted application principal |
| Unknown key or key-resolver outage | Controlled failure; no decode-only fallback |
| Malformed or oversized bearer input | Bounded rejection before protected work |
| Valid token selecting another user’s private document | Authentication can pass; object authorization must deny the action |
For time cases, state the configured tolerance and use fixed clock values just inside and outside its boundaries. Include the exact exp instant with zero tolerance: it must be rejected. Never change production clocks or wait for a real credential to expire to run this suite.
Count principal creation, protected handler invocations, database changes, and queued business work. A final error response cannot prove that a handler did not already run. Security logging on rejection may be intentional; distinguish it from the protected operation. These are proposed acceptance criteria, not reported execution results.
Error-path operator workflow
On a verification failure, terminate authentication and return the API’s documented generic failure. If key retrieval is unavailable, use the documented controlled service-failure behavior without granting access. Preserve internal categories such as jwt_signature_invalid, jwt_audience_denied, jwt_expired, or jwt_key_unavailable; do not expose detailed verifier exceptions to clients.
Record the route identifier, policy revision, library version, stable failure category, and synthetic fixture label. Exclude bearer credentials, raw claims, authorization headers, and attacker-controlled key URLs from general logs. OWASP recommends generic external errors and sanitized security audit records.
If a rejected fixture reaches a protected handler, block the patch. Trace middleware registration, principal assignment, and exception handling before changing a claim rule. Remove catch-and-decode fallbacks, reset the disposable state, and rerun both allowed and denied cases against the corrected revision.
Failure modes
The patch replaces verification with decoding. Read the library’s documented operation and trace its result. A parsed claim is still sender-controlled until the complete acceptance policy succeeds.
A signature check is treated as the whole contract. Require issuer, audience, time, subject, and purpose rules too. Use correctly signed negative fixtures to exercise them.
Missing claims inherit permissive defaults. Configure required claims separately when necessary and test each omission independently.
A key ID or header URL selects a new trust source. Restrict resolution to configured issuer keys and trusted retrieval locations. Reject unresolved keys without a weaker path.
A generic JWT header is treated as proof of access-token purpose. Make different token profiles reject each other’s tokens using the issuer’s actual contract.
Tests stub out the middleware being changed. Exercise the real verifier, resolver, principal construction, and handler wiring with disposable credentials.
FAQ
Does RFC 7519 require every JWT to contain an expiration?
No. Its registered claims are optional in the base format. The application profile determines required claims. This API example requires expiration, issuer, audience, and subject; OWASP recommends issuer, audience, and expiration by default for API access control.
Does a valid signature authorize an API operation?
It establishes integrity under the verified key and algorithm. The token must also satisfy the complete acceptance policy, and the resulting principal still needs permission for the requested action and object.
Does expiration provide immediate logout or replay prevention?
No. A still-valid bearer token can remain acceptable after logout unless the system implements its documented invalidation policy. OWASP discusses denylisting on explicit session termination. Replay prevention and session invalidation need their own design and tests; an exp check alone does not supply them.
Should a coding agent implement JWT cryptography directly?
Use a maintained verification library and its current documentation. The review task is to configure and integrate that verifier correctly, including the profile rules it does not implement, rather than writing signature primitives or an ad hoc JOSE parser.
Reader next step
Choose one token-accepting route in the next coding-agent patch. Write its accepted token profile, trace where the first authenticated principal is created, and add a correctly signed wrong-audience fixture plus a missing-expiration fixture. Approve the revision only when legitimate access works and rejected tokens cannot create identity, reach protected handlers, or cause business effects.