OAuth State Generator
Generate secure random state tokens (128 bits) for CSRF protection in OAuth 2.0 flows. Recommended by RFC 6749.
—
Signed OAuth state: encoding intent in the state parameter
There are two schools of thought for the OAuth 2.0 state parameter. The random opaque approach generates a high-entropy string, stores it server-side, and compares on callback. The signed claims approach embeds structured data — CSRF nonce, return URL, user intent, A/B variant — inside the state itself and proves integrity with an HMAC. Both prevent CSRF; signed state additionally lets the callback handler reconstruct context without server-side session storage, which is decisive for serverless and edge runtimes (Cloudflare Workers, Vercel Edge, AWS Lambda) where sticky sessions are expensive or impossible.
A typical signed state layout encodes a JSON payload and appends an HMAC-SHA256 tag, separated by a dot:
payload = base64url(JSON.stringify({
csrf: random(16), // anti-CSRF nonce
return_url: "/dashboard",
intent: "signup", // signup | login | link
variant: "B", // A/B test arm
iat: 1716902400, // issued-at (unix)
ttl: 600 // 10 minutes
}))
tag = base64url(HMAC_SHA256(STATE_SECRET, payload))
state = payload + "." + tag
Validation flow on the callback
Split on the dot, recompute the HMAC over the payload, and compare in constant time (crypto.timingSafeEqual). Only after the tag matches should you parse the JSON. Then check iat + ttl > now to enforce a 5–10 minute window — short enough to defeat replay, long enough for legitimate users on slow networks. Reject anything older. Finally, validate return_url against an allowlist of same-origin paths to prevent open redirects.
JWT vs custom HMAC
You can use a JWT (jsonwebtoken, jose) for the same job — the exp/iat claims and HS256 signature map directly onto signed state. JWT is overkill for a value that lives 10 minutes: the header adds bytes and the algorithm-confusion footguns ("alg":"none") are real. Custom HMAC keeps the state shorter for URL budgets and avoids surprise parsers. libsodium / tweetnacl offer crypto_auth if you want HMAC without sourcing it from your standard library.
Secret hygiene and rotation
Pick a 256-bit secret (32 random bytes), store in STATE_SECRET environment variable, never check into git. Rotate by keeping a small key ring — current and previous secrets — verifying against any active key for the TTL window. After rotation, the old key can be retired in 10 minutes since no in-flight state outlives its TTL. OAuth 2.1 still recommends state alongside the now-mandatory PKCE; they defend different layers.
FAQ
Should I prefer signed state over a server-side store? Yes if you are stateless (serverless, edge). No if you already maintain a session store — random state is simpler and the state value stays opaque.
Is HMAC-SHA256 strong enough? Yes — with a 256-bit secret it is the same primitive that backs HS256 JWTs, AWS request signing and TLS PRFs. The weak link is secret rotation discipline, not the algorithm.
How long should the TTL be? 5–10 minutes for interactive flows. Longer windows leak through redirects and shoulder-surfing; shorter windows fail real users on flaky connections.
Does signed state make PKCE unnecessary? No. PKCE binds the authorization code to the original client; signed state defends the callback URL against CSRF. They mitigate different attacks and OAuth 2.1 requires both for public clients.
Related Tools
OAuth State Parameter Generator
Generates a random OAuth state value using the browser crypto API, from 16 to 64 bytes and encoded as base64url, to bind a login callback against CSRF.
JWKS EC Generator (P-256/P-384/P-521)
Generate a JWKS (JSON Web Key Set) with EC key (P-256/P-384/P-521) ready for /.well-known/jwks.json endpoint, with kid and use.
CSRF Token Generator
Generate random CSRF tokens (32 bytes) in hex or base64url using browser Crypto API.
Random Fake JWT Generator
Generate a JWT with random header/payload/signature (no valid signature) for mocking OAuth flows in local development.
OAuth PKCE Generator
Generate an OAuth PKCE pair (code_verifier and S256 code_challenge) for secure auth flows in mobile apps and SPAs. Mitigates code interception attacks.
Rock Band Name Generator
Draw rock band name ideas from a list of adjectives and nouns, the way most bands land on theirs: two words that sound good shouted at a gig.