Lion Cipher Lab
Harden the OAuth authorization request with PAR and JAR (RFC 9126 / 9101)
- Identity & Access Management
- Advanced
- ~80 min
- Free · no account required
Why it matters
Most OAuth hardening advice targets the token: PKCE binds the code to the client, DPoP binds the token to a key, refresh rotation limits theft. But before any of that, the authorization REQUEST itself travels through the user-agent as plain front-channel query parameters -- client_id, redirect_uri, scope, state -- and the user-agent is exactly where an attacker sits. Anything in that URL can be inspected, logged into referrer headers and proxies, and rewritten in flight: bump scope from 'read' to 'read admin', swap redirect_uri to exfiltrate the code, or substitute a whole request object. The…
What you'll learn
- reading the OAuth 2.0 authorization-code flow as two channels: a FRONT channel (browser redirects carrying client_id, redirect_uri, scope, state as query parameters) and a BACK channel (the client POSTing the code to the token endpoint)
- seeing concretely why the front channel is attacker-reachable: an interposing script rewrites scope from 'read' to 'read admin' in flight and the naive AS mints a code bound to the elevated scope
- implementing Pushed Authorization Requests (PAR, RFC 9126): the client POSTs parameters to a /par endpoint over the back channel and receives a one-time, short-TTL request_uri
- enforcing require_pushed_authorization_requests server-side so the AS REJECTS any front-channel /authorize call that lacks a request_uri, ignoring query parameters entirely
- implementing JWT-Secured Authorization Request (JAR, RFC 9101): wrapping the request object as a signed JWT and verifying the JWS compact signature by hand with hmac and base64url
- watching the AS reject a FORGED request object whose signature was produced with the wrong key -- authenticity and integrity of the request itself
- the named failure modes: PAR protects request integrity and confidentiality but NOT client authenticity without client auth or JAR; request_uri must be one-time and short-TTL to resist replay; exact redirect_uri matching still required
- the judgment of why FAPI 2.0 mandates PAR, how this complements PKCE/DPoP/mix-up defenses rather than replacing them, and the standing rule to never hand-roll OAuth
Steps in this lab
- The authorization request, and why its integrity is the gap
- How PAR and JAR close the front-channel gap
- Set up your local, authorized, disposable lab
- Build the mock Authorization Server (PAR + JAR aware)
- Build the client and the browser/tamper driver
- STAGE 1 -- the hole: tamper the front channel and elevate scope
- STAGE 2 -- PAR: push the request; the front channel has nothing to tamper
- STAGE 3 -- JAR: sign the request object; the AS rejects a forgery
- The judgment: named failure modes, FAPI 2.0, and never hand-roll