Sachith Dassanayake Software Engineering OAuth2/OIDC and PKCE done right — Patterns & Anti‑Patterns — Practical Guide (Mar 18, 2026)

OAuth2/OIDC and PKCE done right — Patterns & Anti‑Patterns — Practical Guide (Mar 18, 2026)

OAuth2/OIDC and PKCE done right — Patterns & Anti‑Patterns — Practical Guide (Mar 18, 2026)

OAuth2/OIDC and PKCE done right — Patterns & Anti‑Patterns

body { font-family: Arial, sans-serif; line-height: 1.6; margin: 2rem; max-width: 720px; }
h2 { border-bottom: 2px solid #333; padding-bottom: 0.3em; margin-top: 2em; }
h3 { margin-top: 1.5em; }
pre { background: #f6f8fa; padding: 1em; overflow-x: auto; border-radius: 4px; }
code { font-family: Consolas, monospace; }
p.audience { font-weight: bold; font-style: italic; }
p.social { margin-top: 3em; font-size: 0.9em; color: #555; }

OAuth2/OIDC and PKCE done right — Patterns & Anti‑Patterns

Level: Experienced software engineers

Current as of March 18, 2026. Covers OAuth 2.1 drafts (latest standards expected), OpenID Connect Core 1.0, and widespread PKCE patterns.

Introduction

OAuth 2.0 and OpenID Connect (OIDC) are essential protocols for secure delegated authentication and authorisation in modern applications. The Proof Key for Code Exchange (PKCE) extension significantly improves security, especially for public clients or single-page apps.

This article distils best practices, common pitfalls, and validation techniques for OAuth2/OIDC with PKCE, ensuring implementations are robust, secure, and maintainable in 2026.

Prerequisites

  • A solid understanding of OAuth 2.0 fundamentals (RFC 6749) and OIDC basics (OpenID Connect Core 1.0).
  • Familiarity with OAuth 2.1 (drafts evolving since 2021, stabilising around 2025–26) which subsumes PKCE as mandatory for authorization code flows.
  • Modern cryptography primitives and safe random generation functions, e.g., Web Crypto API or libsodium.
  • Development environment supporting secure HTTPS endpoints and secure storage mechanisms for tokens.
  • Understanding of the app architecture: whether client is a Single Page Application (SPA), native app, or server-side web app.

Hands-on steps: Implementing OAuth2/OIDC with PKCE the right way

1. Choose Authorization Code Flow with PKCE

Since OAuth 2.1, the implicit flow is deprecated due to security vulnerabilities and replaced by authorization code flow with mandatory PKCE for all clients, including SPAs and native apps. PKCE enhances security by mitigating authorization code injection attacks.

2. Generate PKCE Code Verifier and Code Challenge

The code verifier is a high-entropy cryptographic random string (43–128 chars), used to derive the code challenge.

The code challenge is derived as either the S256 hash of the verifier (recommended) or the plain verifier (only if S256 unsupported, which is exceedingly rare nowadays).

// Generate PKCE code verifier (example in JavaScript)
function generateCodeVerifier() {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64UrlEncode(array);
}

function base64UrlEncode(buffer) {
  return btoa(String.fromCharCode(...buffer))
    .replace(/=/g, '')
    .replace(/+/g, '-')
    .replace(///g, '_');
}

function generateCodeChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  return crypto.subtle.digest('SHA-256', data).then(hashBuffer => {
    const hashArray = new Uint8Array(hashBuffer);
    return base64UrlEncode(hashArray);
  });
}

3. Include Code Challenge in Authorization Request

When redirecting to the authorisation endpoint, add these query parameters:

  • code_challenge — The string from generateCodeChallenge
  • code_challenge_method=S256 — Specify the hashing method

Example OAuth 2.0 authorisation URL:


https://auth.example.com/authorize?
  response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback
  &scope=openid%20profile%20email
  &state=random_state_value
  &code_challenge=xyz123abc...
  &code_challenge_method=S256

4. Exchange Authorization Code for Tokens

During the token request, use the code verifier like this (POST to the token endpoint):

POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback
&client_id=YOUR_CLIENT_ID
&code_verifier=original_code_verifier

The authorization server validates the code_verifier against the stored code_challenge, adding a crucial security check to prevent intercepted codes from misuse.

5. Validate ID Token and Access Tokens Correctly

When using OIDC, an ID Token is returned. Validation steps include:

  • Verifying signature if JWT (JSON Web Token)
  • Checking iss (issuer), aud (audience/client ID), exp, and iat claims
  • Verifying nonce matches the one sent in the initial auth request (to prevent replay attacks)

These steps are often handled by validated OIDC client libraries (e.g., oidc-client-js, msal, openid-client in Node.js, AppAuth libraries).

Common pitfalls

1. Using the Implicit Flow Instead of PKCE

The implicit flow is prone to access token leakage via URL fragment, lacks refresh tokens, and is no longer recommended. Always prefer authorization code flow + PKCE even for purely browser-based apps.

2. Omitting Code Challenge or Using Plain Method

Not including a code challenge or using the insecure plain method undermines PKCE’s security. Modern identity providers almost always require code_challenge_method=S256.

3. Reusing Code Verifiers or Predictable Values

The code verifier must be freshly generated and cryptographically random per auth request. Reusing or using low-entropy values facilitates swapping attacks.

4. Not Validating ID Token Signature or Claims

Assuming the ID Token is trustworthy without robust validation opens risks of token forgery and replay. Always validate tokens server-side if possible.

5. Leaking Client Secrets in Public Clients

In public clients (mobile, SPA), avoid embedding or exposing client_secret. Such clients should rely solely on PKCE and omit a client secret.

6. Ignoring HTTPS

OAuth flows, especially those transporting tokens and PKCE verifiers, must strictly use HTTPS to prevent MITM attacks.

Validation — Testing your implementation

  • Use OAuth playground tools (e.g., OAuth 2.0 Debugger) to verify token exchange and PKCE parameters.
  • Test your application with public OAuth providers (Google, Microsoft, Okta) supporting PKCE to confirm interoperability.
  • Perform penetration testing or use static analysis tools on your OAuth code path focusing on PKCE and token handling.
  • Check token expiry and refresh token flows behaviour in your client implementation.

Checklist / TL;DR

  • [✔] Always use Authorization Code Flow with PKCE for SPAs, mobile, and native apps.
  • [✔] Generate secure, random code verifiers (43–128 chars).
  • [✔] Use code_challenge_method=S256 exclusively.
  • [✔] Send code challenge in authorisation requests and verifier in token requests.
  • [✔] Validate ID tokens fully: signature, issuer, audience, nonce, and timestamps.
  • [✔] Never embed client secrets in public clients; rely on PKCE instead.
  • [✔] Use HTTPS everywhere in OAuth flows.
  • [✔] Avoid deprecated flows like implicit or resource owner password flow.

When to choose Authorization Code + PKCE vs Other Flows

Authorization Code + PKCE is the modern default for almost all clients, especially public clients:

  • Web server apps can use code flow + client secret (confidential clients).
  • <

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Post