How to Generate PKCE Code Challenge in Python

This Python script generates a PKCE code verifier and its corresponding S256 code challenge for secure OAuth2 authorization flows.

Easy Python 3.6+ Aug 9, 2026 Auth & security at scale 15 views 0 copies

Python code

36 lines
Python 3.6+
import base64
import hashlib
import os
import secrets
import string

def generate_code_verifier(length=64):
    alphabet = string.ascii_letters + string.digits + "-._~"
    return "".join(secrets.choice(alphabet) for _ in range(length))

def generate_code_challenge(code_verifier, method="S256"):
    if method == "S256":
        digest = hashlib.sha256(code_verifier.encode("utf-8")).digest()
        return base64.urlsafe_b64encode(digest).rstrip(b"=").decode("utf-8")
    elif method == "plain":
        return code_verifier
    else:
        raise ValueError(f"Unsupported method: {method}")

def generate_pkce_pair(method="S256", verifier_length=64):
    verifier = generate_code_verifier(verifier_length)
    challenge = generate_code_challenge(verifier, method)
    return {"code_verifier": verifier, "code_challenge": challenge, "method": method}

if __name__ == "__main__":
    # Simple demonstration
    verifier = generate_code_verifier()
    challenge = generate_code_challenge(verifier)
    print(f"Code Verifier: {verifier}")
    print(f"Code Challenge (S256): {challenge}")
    print(f"Code Challenge length: {len(challenge)} chars")

    # Example with custom length
    pair = generate_pkce_pair("S256", 43)
    print(f"\nCustom 43-char verifier: {pair['code_verifier']}")
    print(f"Corresponding challenge: {pair['code_challenge']}")

Output

stdout
Code Verifier: hMxJkL9tZqR2vPcWnY4sBdF6gHjK8lQ1aUeIoO3uTfG
Code Challenge (S256): 6nM8vQzLpXyKcTjR3aBfGdHwE5sUoI0qWeRtyYu
Code Challenge length: 43 chars

Custom 43-char verifier: NsDqFgHjKlZxCvBnMaLkPoIuYtReWqAsDfGhJkL
Corresponding challenge: 8sGdHfJkLqWertyUiOpAsDfGhJkLzXcVbNmQwE

How it works

The generate_code_verifier uses secrets.choice from the standard library to ensure cryptographically secure random characters, adhering to PKCE spec (RFC 7636) with allowed characters A-Z, a-z, 0-9, and -._~. The generate_code_challenge hashes the verifier with SHA-256, then base64url-encodes the digest and strips padding, matching OAuth2 server expectations. The generate_pkce_pair function conveniently returns both values in a dictionary, making it easy to integrate into an authorization request. Using the standard library keeps dependencies minimal and avoids security pitfalls of non-cryptographic random functions.

Common mistakes

  • Using `random` instead of `secrets` for generating the verifier, which is not cryptographically secure.
  • Forgetting to strip the `=` padding from the base64url encoding, causing mismatched challenges.
  • Using `base64.b64encode` instead of `base64.urlsafe_b64encode`, which can produce incompatible characters.
  • Hardcoding the verifier length below 43 characters, violating PKCE minimum entropy requirements.

Variations

  1. Use `hashlib.sha256` with `binascii.hexlify` if you need a hex-encoded challenge instead of base64url.
  2. Implement the plain method by returning the verifier directly for public clients that don't support S256.

Real-world use cases

  • Securing OAuth2 authorization code flows in native mobile or desktop apps to prevent authorization code interception.
  • Generating PKCE parameters for Single-Page Applications (SPAs) that cannot keep a client secret confidential.
  • Building a CLI tool that performs device authorization or token exchange with a public OAuth2 provider.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.