BIND · PROVE · CONSUME
OAuth authorization code and PKCE
Real challenge computation. Inspectable request bindings. No real credentials.
Stage ledger
Exact protocol evidence
Bind a code to a client-held proof
An authorization code is not an access token. This experiment creates a local code record containing the public client identifier, exact redirect URI, challenge method, challenge, expiry and used flag. A token exchange checks those bindings before consuming the code. The browser calculates a real SHA-256 digest and unpadded base64url encoding for S256. All codes, states and tokens exist only inside this exercise; no account is connected and no network request is sent. The displayed token is a fictional label, not a credential you can use.
Prepare and inspect the challenge
Verifier accepts between forty-three and one hundred twenty-eight ASCII unreserved characters: letters, digits, hyphen, dot, underscore and tilde. The initial value is a published reproducible example, not a secret suitable for deployment. Fresh random verifier generates thirty-two random bytes with the browser cryptographic random source and encodes them as forty-three characters. Challenge method selects S256 or legacy plain. Allow legacy plain changes this fixture server’s policy; it is disabled initially. With plain disabled, selecting that method rejects the authorization request rather than silently downgrading. Exact evidence shows the actual challenge.
Exercise independent rejection boundaries
Fault selects the change to apply. Wrong verifier submits a different proof. Stolen code submits the observed challenge as a verifier, representing an interceptor who sees the authorization request but lacks the client secret proof. Client mismatch and Redirect mismatch change the respective code-bound fields. Callback state mismatch stops the client before it makes a token request; this is a separate check from PKCE. Consent denied produces no authorization code. Redeem twice first consumes a valid code, then rejects reuse and revokes the previously issued local token under this fixture’s policy. Compare Redeemed with Token active to see why those flags are different.
Run concrete comparisons
Restore defaults and Show final result: the default exchange activates the fictional token. Select Wrong verifier and inspect the failed exchange; no token is issued. Select Stolen code with S256 to get another rejection. Now choose legacy plain and explicitly enable Allow legacy plain. The same interception succeeds because the challenge itself exposes the proof in this deliberately weak comparison. Restore defaults afterward. Choose Redeem twice and inspect the first issuance with Next stage before viewing the final revocation. Earlier stage snapshots keep their historical status even after the later reuse is rejected.
Explore expiry without waiting
Code lifetime is the validity window in simulated seconds, from one to one hundred twenty. Redemption delay sets the simulated exchange time, from zero to one hundred twenty. Set lifetime to sixty and delay to fifty-nine: the exchange succeeds. Set delay to sixty: it is expired at the exact boundary. This modeled delay is independent of the viewing clock. Changing playback speed cannot extend a code’s lifetime or change a cryptographic result. Invalid verifier input stops before any authorization code is created.
Control the inspection
Play reveals the computed stages over sixty viewing seconds, even when a run stops at an early rejection. Pause freezes the selected evidence. Next stage advances one checkpoint, Restart returns to the start of the same result, and Show final result jumps to its terminal state. Speed offers half, normal and double viewing pace; Inspect time allows backward and forward scrubbing. Every protocol edit prepares a new local transaction and rewinds playback. Restore defaults reinstates the published verifier and initial options. The stage ledger and structured text are alternatives to the diagram.
Know the security and modeling limits
PKCE is not public-client authentication and does not make a browser immune to script compromise. State in this fixture is an independently generated callback-binding value. There is no actual redirect, login session, consent UI, HTTP endpoint, resource server, refresh-token rotation, scope negotiation or persistent token database. The client identifier and reserved example redirect are fixed teaching constants. Code storage is a single local object rather than an atomic multi-request server transaction. Displaying the verifier is educational; production logs must not expose such proofs. The legacy comparison is intentionally unsafe and does not recommend enabling plain in a new deployment.
Protocol references: PKCE specification and OAuth authorization code specification.