OAuth failures usually do not come from the protocol itself. They come from how teams wire it up. In practice, one input tends to dominate the risk surface: redirect_uri. If an authorization server accepts values that are not locked to an exact per-client allowlist entry, an attacker can steer an authorization code or token to infrastructure they control. That can end in account takeover even when the client secret never leaks. ⚠️
A solid defensive review is mostly a search for four things: loose redirect_uri checks, missing PKCE, weak or absent state validation, and risky token handling after issuance. The most useful monitoring signals follow the same pattern: callback URLs that fall outside the registered allowlist, and tokens that suddenly appear from a network or region that does not fit the normal profile.
This is defensive guidance for authorized environments only. The goal is to help defenders audit implementations, spot abuse, and close gaps early. The overall standard to line up with is RFC 9700, published in January 2025, and the behavior maps cleanly to MITRE ATT&CK T1528, T1550.001, and T1078.
The biggest OAuth risk is weak
redirect_urivalidation. Match the complete URI per client: scheme, host, port, and path. No wildcards. No regex.PKCE should be required everywhere. If an attacker intercepts the authorization code but lacks the verifier, the code is useless.
statemust be generated and checked. It is your CSRF and login-fixation defense.Validate
redirect_uritwice. Check it at the authorize step and again during token exchange.Detection is straightforward if you log the right fields. Watch for off-allowlist callback requests and tokens used from a new network or geography right after issuance. ✅
An OAuth misconfiguration is an implementation flaw in either the client or the authorization server that allows someone to obtain a code, token, or effective account access they should not have. The protocol design is not the problem here. The breakdown is almost always in validation, policy, or storage.
Typical failure points include:
accepting the wrong
redirect_urinot enforcing PKCE
missing
statechecksgranting scopes that are too broad
storing tokens in unsafe places
Because OAuth tokens effectively represent identity and delegated access, these mistakes are not minor. They are often direct account-takeover conditions. 🚨
Among these controls, redirect_uri matters most because it defines where the server sends sensitive material after authentication. If that destination can be manipulated, the server is doing the attacker’s delivery work for them.
Across real implementations, the same categories appear repeatedly:
Loose
redirect_urivalidation
- The attacker gets the code or token sent to a server they control. - Review signal: the requested callback is not an exact match for the registered allowlist. - Fix: exact per-client allowlist matching.
No PKCE
- The attacker intercepts the authorization code and redeems it. - Review signal: a public client exchanging codes without PKCE. - Fix: require PKCE for all clients.
Missing or unchecked
state
- The attacker abuses CSRF or login-fixation behavior. - Review signal: authorization requests without a valid state, or callbacks where state is ignored. - Fix: generate it, bind it to the session, and validate it on return.
Implicit flow still enabled
- Tokens can be exposed in the browser URL fragment. - Review signal: response_type=token in authorize traffic. - Fix: use authorization code flow with PKCE.
Scopes are broader than necessary or pre-consent is overly permissive
- The token provides more access than the client actually needs. - Review signal: granted scopes exceed the normal baseline. - Fix: least-privilege scope design. 📌
The pattern underneath all of this is simple: strict validation plus least privilege.
Public breach research has shown how dangerous partial validation can be. A common pattern is checking only the callback domain while ignoring the exact path. That sounds close to safe, but it is not. If the path is uncontrolled, redirect chains can still leak authorization material.
The practical lesson is not subtle: validate the entire redirect_uri string, not just part of it. That means origin and path together, matched exactly. Then perform the same validation again when the client exchanges the code for a token over the back channel. That second check matters because it closes a gap the attacker cannot easily reach remotely. 🛠️
Two signals are especially valuable:
1. an authorize request that carries a redirect_uri outside the client’s registered allowlist 2. a token that is used from an unfamiliar place shortly after it was issued
If your logs capture the requested callback URL and whether it matches the client’s registered configuration, a mismatch is either an attack attempt or a broken integration that still needs immediate review.
title: OAuth Authorize Request With an Off-Allowlist redirect_uri
id: 11111111-darkpwn-illustrative
status: experimental
logsource:
product: application
service: oauth
detection:
selection:
endpoint|contains: '/authorize'
suspect:
redirect_uri|contains: ['@', '%2f', '%2F', '/../', 'localhost', '..']
mismatch:
redirect_uri_allowlisted: 'false'
condition: selection and (suspect or mismatch)
falsepositives:
- Newly registered legitimate callback URLs (update the allowlist, then this clears)
level: highThis detection works because off-allowlist redirects and obvious traversal or redirect tricks leave recognizable request-time artifacts. Even when an attempt is not malicious, you still want it surfaced quickly. ⚠️
Once a token is stolen, the API traffic often looks perfectly normal. The requests can be syntactically identical to legitimate use. That means content matching is weak; behavior is where the signal lives.
index=oauth (event=token_issued OR event=token_used)
| transaction token_id maxspan=15m
| eval issue_net=mvindex(src_subnet,0), use_net=mvindex(src_subnet,-1)
| where issue_net!=use_net
| table _time, client_id, token_id, issue_net, use_net, scopeThe idea is to compare the network at issuance with the network seen during early token use. A mismatch inside a short window can be a strong indicator of compromise. For mature detection, build baselines around:
source network
geography
refresh cadence
normal scope usage
Then alert on deviation: a new subnet after the token is established, impossible geographic movement, or scope activity that exceeds the token’s historical pattern. ✅
When you review an OAuth implementation, inspect both every client and the authorization server.
redirect_uri
- Confirm exact matching against a per-client allowlist. - Reject wildcards, regex, and path-prefix logic. - Test bypass candidates like @evil.com, app.com.evil.com, %2f, and /../.
PKCE
- Verify it is mandatory for all clients, not only public ones.
state
- Confirm generation, session binding, and return-path validation.
Flow choice
- Make sure implicit flow is disabled. - Prefer authorization code flow with PKCE.
Token exchange
- Verify redirect_uri is checked again during code redemption.
Configuration hygiene
- Flag localhost callbacks, wildcard redirects, unnecessary pre-consent, and excessive default scopes. 🛠️
The core defensive pattern from RFC 9700 is straightforward:
exact-match
redirect_urivalidationPKCE for every client
validated
stateno implicit flow
second
redirect_uricheck at token exchange
A few additional controls matter just as much operationally:
grant only the scopes the client actually needs
store tokens safely, ideally in HttpOnly cookies rather than local storage
support token revocation
on mobile, prefer Android App Links and iOS Associated Domains instead of raw custom URI schemes 🚀
Teams repeatedly miss the same issues:
They do not log authorize requests.
- If you cannot see the callback request, you will miss off-allowlist activity entirely.
They try to detect stolen tokens from content alone.
- Legitimate and stolen tokens usually produce the same API calls.
They rely on regex or wildcard callback validation.
- This is one of the most common root causes of bypass.
They treat the review as a one-off task.
- These flaws can sit quietly for months before anyone notices. 📌
Use this as a recurring review baseline:
Enforce exact-match
redirect_urivalidation for scheme, host, port, and path on a per-client basis.Disallow wildcard and regex callback matching, and require HTTPS.
Require PKCE for all clients, validate
state, and disable implicit flow.Check
redirect_uriagain during token exchange.Apply least-privilege scopes and remove unnecessary pre-consent.
Log authorize requests and alert on off-allowlist or open-redirect-style
redirect_urivalues.Baseline token use by network, geo, and scope; alert on post-issuance deviation.
Store tokens in HttpOnly cookies, support revocation, and align the overall design to RFC 9700. ✅
The highest-return control is a recurring configuration audit. Wildcard callbacks, localhost redirects, missing PKCE, and bloated scopes are often sitting in plain sight long before anyone exploits them.
If you only remember one thing, make it this: an OAuth defensive review is primarily a redirect_uri review. Start there, then verify PKCE everywhere, enforce state, and confirm the callback is checked again during token exchange. Detection should cover both the front of the flow and the aftermath: bad callback destinations at request time, and abnormal token behavior after issuance. 🔒
Weak redirect_uri validation is usually the most severe. If the authorization server does not require an exact allowlist match for each client, an attacker can redirect the code or token to infrastructure they control. The full callback URI must be checked: scheme, host, port, and path.
Log authorize requests and alert when a requested callback is not an exact match for the client’s registered allowlist. Also look for open-redirect indicators such as @, %2f, extra subdomains, traversal patterns, and tokens used from a new network or geography shortly after issuance.
Yes. PKCE binds the authorization code to a code_verifier the attacker does not possess, which prevents successful token exchange even if the code is intercepted. RFC 9700 recommends PKCE for both public and confidential clients.
RFC 9700 is the OAuth 2.0 Security Best Current Practice document released in January 2025. It formalizes defensive lessons learned from real-world failures, including exact callback matching, PKCE for all clients, avoidance of implicit flow, and validation of the state parameter.
🔍 TL;DR Summary
🔐 The most critical OAuth review item is exact-match
redirect_urivalidation per client.🧷 PKCE should be mandatory everywhere, and
statemust be generated and validated.🚫 Avoid implicit flow and check
redirect_uriagain during token exchange.🕵️ Detect abuse by logging authorize requests and flagging off-allowlist callbacks.
🌐 Stolen tokens are best found through behavior: new networks, impossible geo shifts, and unusual scope use after issuance.
No posts

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.