Safeguard
Security Guides•

OAuth state vs nonce vs PKCE: what does each one stop?

State, nonce and PKCE look alike but guard different attacks. A plain guide to which one blocks CSRF, ID token replay and authorization code injection.

Safeguard Security Team
4 min read

State links an OAuth response to the request that started it, which stops CSRF. Nonce ties an OpenID Connect ID token to one login attempt, which stops replay. PKCE ties an authorization code to the client that asked for it, which stops code injection and theft. They overlap, but they are not the same.

The three values

ValueSent inComes back inMain job
stateAuthorization requestRedirect to your appBind the response to your browser session (CSRF)
nonceOIDC authorization requestID token claimBind the ID token to one session (replay)
code_verifier and code_challengeChallenge in the request, verifier at token endpointNot returnedBind the code to the client that requested it

State

The long established CSRF countermeasure, per RFC 9700, is for the client to pass a random value in the state parameter that links the request to the redirect and to the user agent session. When you check it on return, you reject responses your browser never asked for.

Two details from the RFC. State must be one time use and securely bound to the user agent. And if you also use state to carry app data, protect it against tampering and swapping.

Nonce

The OpenID Connect spec describes the nonce as a string value that associates a client session with an ID token and mitigates replay attacks. You send it in the request, the server copies it into the ID token, and your client must verify that the claim equals what it sent. The spec says it needs enough entropy that attackers cannot guess it.

PKCE

PKCE (RFC 7636) protects against authorization code injection. RFC 9700 explains the idea: when an attacker injects a code, the check of the verifier fails, because the code is tied to a challenge that does not match the client's verifier. PKCE also means a stolen code cannot be redeemed at the token endpoint without the verifier.

Which do you need

RFC 9700 says:

  1. Public clients must use PKCE. For confidential clients it is recommended.
  2. PKCE also gives CSRF protection, but only if the authorization server supports it. If it does not, you must use state or nonce.
  3. In OpenID Connect flows, nonce can provide CSRF protection.
  4. Otherwise, one time CSRF tokens in state, bound to the user agent, are required.

A safe default for a new app: use PKCE, and still send state and nonce. They are cheap, and defence in depth helps when one piece is misconfigured.

Mistakes to look for in review

  • A static or guessable state value.
  • State generated but never checked on return.
  • Nonce checked for presence but not for equality.
  • PKCE with the plain method when S256 is available. RFC 7636 says a client that can use S256 must use it.
  • Reusing the same verifier across requests.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how code findings point to a file and line, the same way a review would flag a state value that is never checked.

Quick check

If I use PKCE, can I drop state?

RFC 9700 allows PKCE to replace state for CSRF protection only if you have confirmed the authorization server supports it. Many teams keep state anyway.

Does nonce apply to plain OAuth without OpenID Connect?

No. Nonce is an OpenID Connect parameter tied to the ID token. Plain OAuth relies on state and PKCE.

Safeguard's SBOM and dependency scanning shows which OAuth client libraries you ship, which helps when a library advisory affects how these values are handled. Try a free scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.