Step 1. Generate a Proof Key

Generate a code_verifier — a cryptographically random string — and the corresponding code_challenge.

JK9biikOpe8nmB2MojgAELkqDPj3cDDEIH-hy1tsGOs
Keep this secret. It is required for the final /token exchange.
scMWZ5jqkipmM8aPdgg2enqMacMXPXlQrnippmPIYVI
The hashed version sent to the authorize endpoint.

Security & Disclaimer

Testing Only

This tool is designed exclusively for educational and troubleshooting purposes, supporting technical teams during client implementations.

To simplify troubleshooting, this tool omits the state and nonce parameters. Please note that omiting state and nonce increases vulnerability to replay attacks. Ensure that both state and nonce validation are implemented in production environments.

No Storage

The generated verifiers are not stored on any server. Everything runs locally in your browser via the Web Crypto API.

Public Client

This tool behaves as a public client. In production, confidential clients must keep their secret server-side.

Generating the code_verifier “manually”

To generate a S256 code_verifier, one must follow these steps:

  • Generate Random Bytes: Create a sequence of cryptographically strong random bytes (typically 32 bytes to result in a 43-character string).
  • Base64URL Encode: Convert those bytes into a Base64URL encoded string. This means replacing + with -, / with _, and stripping any trailing = padding characters.
  • Hashing (for the Challenge): To create the associated code_challenge, apply a SHA-256 hash to the verifier string and Base64URL encode the resulting binary hash.

Bash

Use openssl to handle the entropy and the hashing in a shell environment:

# Generate a 32-byte random verifier
export verifier=$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-43)

# Generate the S256 challenge
export challenge=$(echo -n "$verifier" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')

echo "Verifier: $verifier"
echo "Challenge: $challenge"

C#

In .NET, utilize the RandomNumberGenerator for the verifier and the SHA256 class for the challenge:

using System.Security.Cryptography;
using System.Text;

// 1. Generate Verifier
var bytes = new byte[32];
RandomNumberGenerator.Fill(bytes);
var verifier = Convert.ToBase64String(bytes)
    .TrimEnd('=').Replace('+', '-').Replace('/', '_');

// 2. Generate Challenge (S256)
using var sha256 = SHA256.Create();
var challengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(verifier));
var challenge = Convert.ToBase64String(challengeBytes)
    .TrimEnd('=').Replace('+', '-').Replace('/', '_');

JavaScript

For browser-based applications, the Web Crypto API is the standard for secure random values and hashing.

// Helper for Base64URL encoding
const base64Url = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

async function generatePKCE() {
    // 1. Generate Verifier
    const verifier = base64Url(window.crypto.getRandomValues(new Uint8Array(32)));

    // 2. Generate Challenge (S256)
    const encoder = new TextEncoder();
    const hash = await window.crypto.subtle.digest('SHA-256', encoder.encode(verifier));
    const challenge = base64Url(hash);

    return { verifier, challenge };
}