state is a parameter in the OAuth 2.0 authorization request. The client generates a random value, sends it with the request, and verifies it on the callback. It’s the defense against CSRF attacks on OAuth flows.
The attack it prevents
Without state, an attacker can:
- Start their own OAuth flow and receive a callback URL with an authorization code
- Send that callback URL to the victim (via a link, an iframe, etc.)
- The victim’s browser hits the callback, and now the victim’s session is bound to the attacker’s account
With state, step 3 fails — the victim’s session doesn’t have the matching state, so the callback is rejected.
How to use it
On the authorize redirect:
1. Generate a random value (32+ bytes): state = randomBytes(32)
2. Store it in the user's session (cookie): session.oauth_state = state
3. Include it in the authorize URL: ?state=<value>
On the callback:
1. Read state from the query: req.query.state
2. Read the stored value: session.oauth_state
3. Compare. If different, reject.
Gotchas
- Always use a cryptographically random value. Don’t reuse.
- Store it somewhere that survives the redirect — a cookie, usually. Not in-memory.
- Clear it after use, so replay attacks don’t succeed.
See the full auth glossary for related terms.