Dev.to Security πŸ” Cybersecurity πŸ‘ 0 πŸ“– 3 min read

JWT-Secured Authorization Requests Need Their Own Replay Boundary

JWT-Secured Authorization Requests Need Their Own Replay Boundary An OAuth authorization request is usually a URL full of query parameters. A browser user agent sees that URL, and intermediaries may see it too. RFC 910

JWT-Secured Authorization Requests Need Their Own Replay Boundary

An OAuth authorization request is usually a URL full of query parameters. A browser user agent sees that URL, and intermediaries may see it too. RFC 9101 addresses this design weakness by placing the authorization request in a JSON Web Token called a Request Object. The result can be signed, encrypted, or both, and it can be sent by value in the request parameter or by reference through request_uri.

That change protects the request contents from casual alteration. It does not turn the authorization transaction into a one-time event. A signed Request Object can remain valid after its first presentation unless the authorization server ties it to a short-lived transaction, a client, and a single authorization attempt. Teams that deploy JAR as a signature check alone leave a replay question unanswered.

What the server must validate

The first check is cryptographic. The authorization server must validate the JWS using an algorithm and key that the registered client is allowed to use. Treating the alg header as a free choice invites the familiar key and algorithm confusion problems. The request object's iss should identify the client, and its aud should identify the authorization server. The client_id in the outer request and the claims inside the object must agree, rather than allowing the signed object to describe a different client.

RFC 9101 also requires attention to parameter assembly. Some OAuth parameters can appear outside the Request Object, and the server needs a deterministic rule for duplicates and conflicts. A validator that combines outer and inner parameters with a last-value-wins parser gives an attacker a way to make one component authorize a different request than another component logs.

For signed objects, iss and aud are recommended claims, not decoration. For encrypted objects, the server must decrypt with the configured key and then apply the same validation. A failed signature or decryption should not fall back to the unsigned query parameters.

The Request Object is not the transaction

The safer design treats the validated Request Object as input to an authorization transaction that has its own state. The server records the client, redirect URI, requested scopes, response type, and a transaction identifier before user interaction. It rejects a Request Object that is reused with a different browser session or an expired authorization flow.

An optional jti can support duplicate detection, but its value is only useful when the server stores it for at least the accepted replay window. State correlation still matters because the browser callback must be matched to the authorization attempt that produced it. A signed JWT proves who made a request; it does not prove that the same person is completing it now.

request_uri adds a separate lifecycle problem. The server fetches a request object from a URI and must constrain the scheme, host, redirect behavior, response size, and timeout. The URI should be scoped to the client and expire quickly. A server that fetches arbitrary URLs supplied in an authorization request has created a network primitive with the server's privileges.

Deployment checks

An operator can test the boundary without relying on a special attack tool. Send the same signed request twice and observe whether the second attempt is rejected or enters a distinct transaction. Change the outer client_id while keeping the signed claims intact. Send conflicting parameters inside and outside the object. Point request_uri at a redirect, an internal address, a slow endpoint, and an oversized response. These tests expose whether the server is validating the protocol or merely parsing a JWT.

JAR is useful because it gives authorization parameters integrity and source authentication. It is also easy to implement as a signature gate and forget the surrounding state machine. The deployment should make replay, parameter conflict, and request URI behavior explicit, log those decisions, and fail closed when the transaction cannot be matched.

References

πŸ“° Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.