OAuth 2.0's authorization code grant is the dance behind every "Sign in with Google" button. It works elegantly when configured correctly. It produces account takeovers reliably when the redirect_uri parameter is misconfigured — and that single parameter has produced more CVEs than any other in the OAuth ecosystem.
This lab walks five scenarios. The first is the correct flow. The next four are real-world misconfigurations that show up in audit findings every year. Click each scenario and watch the difference.
Pick a scenario
Why redirect_uri matters so much
In the authorization code grant, the user authenticates with the OAuth provider (Google, Microsoft, Okta), the provider issues a short-lived authorization code, and that code gets delivered back to the application via the redirect_uri the application requested at the start of the flow. The application then exchanges the code (plus its client secret) for an access token.
The redirect step is what makes the dance work. It is also the only place the protocol decides who receives the code. If the OAuth provider sends the code to a URL the attacker controls, the attacker gets the code. From there:
- Public clients (mobile apps, SPAs) without a client secret — the attacker can exchange the code immediately for tokens.
- Confidential clients (server-side apps with a client secret) — the attacker can't exchange the code directly, but if they can submit it to the legitimate app's callback (CSRF-style), the app exchanges it and the attacker now holds the session that gets created.
- With PKCE (Proof Key for Code Exchange) — the attacker still needs the original
code_verifierto exchange the code. PKCE neutralizes most redirect_uri attacks against public clients. This is why modern OAuth guidance requires PKCE for all clients, not just mobile.
The defense checklist
- Exact-match allow-list. Compare the full URI string by equality. No prefix matching, no wildcards, no scheme substitution.
- Allow-list per client. Each registered OAuth client has its own list of permitted redirect URIs — not a global list shared across clients.
- Require PKCE for every flow. Including for confidential clients. PKCE is cheap and breaks the redirect-uri-theft attack even when the URI is leaked.
- Treat redirect URIs like secrets in change management. A pull request that adds a redirect URI to an OAuth client should be reviewed with the same scrutiny as a code change.
- Inventory the URIs you've already authorized. Old test environments, subdomains pointing at decommissioned services, S3 buckets that were once a CI artifact host — all of these have shown up in real attacks.
- Use the state parameter. Bind the OAuth state value to the user's session; reject any callback that doesn't match. Doesn't stop redirect_uri attacks directly, but stops the CSRF-style chain that follows.
The redirect_uri parameter is the steering wheel of the OAuth dance. Any flexibility in how the OAuth provider matches it — wildcards, prefixes, "trust any URL that starts with our domain," forgotten subdomains — becomes an attack surface. Bug bounty researchers report a redirect_uri misconfiguration on a Fortune 500 OAuth provider almost every month.
The fix is unglamorous: exact-match allow-lists, PKCE everywhere, and the discipline to audit which URIs you've registered. None of it requires new cryptography or new tooling. It requires care.
References
Formatted in APA 7. Alphabetized by first author's last name.
- Hardt, D. (Ed.). (2012). The OAuth 2.0 authorization framework (Request for Comments No. 6749). Internet Engineering Task Force. https://datatracker.ietf.org/doc/html/rfc6749
- Lodderstedt, T., Bradley, J., Labunets, A., & Fett, D. (Eds.). (2025). OAuth 2.0 Security Best Current Practice (Request for Comments No. 9700). Internet Engineering Task Force. https://datatracker.ietf.org/doc/html/rfc9700
- Sakimura, N., Bradley, J., & Agarwal, N. (2015). Proof key for code exchange by OAuth public clients (Request for Comments No. 7636). Internet Engineering Task Force. https://datatracker.ietf.org/doc/html/rfc7636