AZ Tools

OAuth 2.0 PKCE Generator

Network

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.

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.

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