OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks
OAuth Grant Types and Their Attack Surface
The OAuth grant types explained for testers: authorization code with PKCE, the legacy implicit flow, client credentials, device code, and what each one exposes.
Published
Each OAuth grant type is a different way to obtain a token, and each exposes a different attack surface, so knowing which flow a target uses tells you where to look. This page covers the grants you will meet and what each one risks. Practice on a free live target.
Authorization code (the default)
The standard interactive flow. The client sends the user to the authorization server, the user approves, and the server redirects back with a short-lived authorization code in the query string. The client then exchanges that code for tokens at the token endpoint, server to server. The code in the browser is useless without that back-channel exchange, which is what makes it safer than handing a token straight to the browser.
GET /authorize?response_type=code&client_id=app123&redirect_uri=https://app.tld/callback&scope=openid%20email&state=xyz HTTP/1.1
Host: auth.example.comThe redirect returns ?code=...&state=..., and the attack surface is redirect_uri validation, state, and the code's single-use handling.
PKCE and why it exists
PKCE adds two parameters to the code flow so a stolen code cannot be redeemed by anyone else:
code_verifier a high-entropy random string the client keeps
code_challenge base64url(SHA-256(code_verifier)), the S256 challenge sent on the authz requestAt redemption the client must present the matching code_verifier. PKCE defeats code interception only, so it is required on public clients but does not replace exact redirect_uri matching or state.
Implicit flow (legacy)
The implicit flow returned the access token directly in the URL fragment (response_type=token), with no code exchange:
response_type=token -> https://app.tld/callback#access_token=...&token_type=BearerA token in the fragment leaks through browser history, any JavaScript that reads location.hash, and analytics scripts that log the full URL. (It is NOT sent in the Referer header, which strips the fragment.) RFC 9700 says clients SHOULD NOT use the implicit grant (and OAuth 2.1 removes it) in favor of authorization code with PKCE. Finding it in use is usually a finding. See implicit flow token leakage.
Client credentials (machine-to-machine)
No user is involved. A service authenticates with its own client ID and secret to get a token for itself:
grant_type=client_credentials&client_id=svc&client_secret=...&scope=reports.readThe attack surface is leaked client secrets and over-broad scopes, not browser redirects.
Resource owner password (avoid)
The user types their password directly into the client, which forwards it to the token endpoint:
grant_type=password&username=alice&password=hunter2&client_id=appThis defeats the entire point of delegation (the client sees the password). RFC 9700 says it MUST NOT be used, and OAuth 2.1 removes it. Treat any use of it as a finding.
Device code
For devices with no browser or keyboard (a TV, a CLI). The device shows a short user_code and a verification_uri. The user approves on their phone, and the device polls the token endpoint. The attack surface is phishing the user into approving the attacker's code, covered in device flow abuse.
Which grant each app uses
Web app with a backend authorization code (+ PKCE)
Single-page app authorization code + PKCE (NOT implicit anymore)
Mobile app authorization code + PKCE
Service to service client credentials
TV / CLI / IoT device code
Legacy / lazy integration implicit or password (a finding)Where to go next
Next, see how OIDC layers identity on top of these flows in OpenID Connect, then attack the most common flaw in redirect_uri manipulation. Or jump straight to a free live target.
← Back to OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks