Skip to content
AZ Tools

OAuth 2.0 PKCE Generator

Generate code_verifier + S256/plain code_challenge for OAuth 2.0 PKCE (RFC 7636).

How to use

  1. Set verifier length (64 is a good default — between 43 minimum and 128 maximum).
  2. Pick S256 (always preferred) or plain (only for legacy servers).
  3. Fill in your client_id, redirect_uri, scope, and OAuth endpoints.
  4. Send the user to the authorization URL. After they're redirected back with ?code=..., run the curl with that code to get tokens.

About this tool

Show

PKCE (Proof Key for Code Exchange, RFC 7636) is the modern OAuth 2.0 flow recommended for ALL public clients — single-page apps, mobile apps, and desktop apps that can't keep a client_secret safe. This tool generates a cryptographically random code_verifier (43-128 chars from the unreserved URI alphabet), derives the code_challenge (SHA-256 base64url-encoded for S256, or the verifier itself for plain), and builds the full authorization URL with state for CSRF protection. The companion curl example shows the token exchange step, with all parameters filled in — just paste in the code from the callback redirect.

Frequently asked questions

S256 vs plain — which should I use?

Always S256. Plain just sends the verifier as the challenge, which gives no protection if an attacker intercepts the authorization request. S256 sends only SHA-256 of the verifier — the verifier itself never appears in step 1, making interception attacks much harder. RFC 7636 says clients should reject plain if S256 is available.

Why these specific characters in the verifier?

RFC 7636 specifies the verifier alphabet as [A-Z][a-z][0-9]-._~ — the unreserved URI characters from RFC 3986. This makes the verifier safe to use anywhere (URLs, headers, form bodies) without escaping.

What's state for?

An opaque random string the client generates per-request and validates on callback. Prevents CSRF: if an attacker tricks your user into clicking a malicious authorization redirect, the state won't match what your app remembered and you reject the response. Always use it.

Where does this run?

Entirely in your browser. The verifier comes from crypto.getRandomValues() and the SHA-256 from crypto.subtle.digest() — both Web Crypto APIs. Nothing is sent anywhere.

Related tools