DEV Community

Cover image for Secure Your Frontend Application (SPA) Login with OAuth 2.1 PKCE
Suresh Ramakrishnan
Suresh Ramakrishnan

Posted on

Secure Your Frontend Application (SPA) Login with OAuth 2.1 PKCE

If your frontend application (SPA) is using auth0, okta, Keycloak, Laravel Passport, or any OAuth-based solution—and you have not yet implemented the PKCE flow for login—you should do it as soon as possible. This is essential to make your application more secure against attackers.

If not, it is like making the key to your secure building publicly accessible, allowing anyone to walk in without restriction.

The Authorization Code Flow with PKCE was introduced in OAuth 2.0 and is now a core requirement in OAuth 2.1 to improve the security of frontend applications. Today, it is considered mandatory to follow this standard.

🔐 Why PKCE is Needed

What is PKCE?

PKCE (Proof Key for Code Exchange) is a security extension to OAuth 2.0 designed to protect the authorization code flow, especially for public clients like Single Page Applications (SPAs). It is now mandatory in OAuth 2.1.

Before diving into PKCE, let’s first understand the security risks in the older approach.

In traditional OAuth implementations, confidential clients used a client_secret to exchange the authorization code for tokens.

However, in SPAs (public clients), storing a client_secret is not secure or recommended, as it can be easily exposed.

👉 Important: SPAs should never store a client_secrt

🚨 Security Risk:

If a client_secret is used in a SPA, it can be easily extracted by an attacker. Combined with an intercepted authorization code, this could allow the attacker to obtain access tokens—leading to serious security issue

How PKCE Solves This Problem

Before getting into the technical flow of PKCE, let’s understand it using a simple analogy.

🎬 Smuggler Analogy (PKCE Simplified with Flow)

Imagine a secure deal where a Smuggler (SPA / Frontend Application) wants to collect cash from a Boss (Authorization Server). To prevent fraud, the Boss uses a clever verification method involving a split note and a serial number.

🔗 Concept Mapping (Analogy → Real Terms)

Smuggler (SPA) → Frontend Application
Boss (Authorization Server) → Auth Server
Split Note → code_challenge
Other Half of Split Note → code_verifier
Serial Number → SHA-256 (used to derive challenge)
Courier → HTTP Requests
Cartel → User Database
Pickup Code → authorization_code
Cash → access_token

Smuggler Analogy Flow Diagram

Smuggler Analogy (PKCE)Flow Diagram

Step-by-Step Flow Explanation (Analogy)

1. Smuggler prepares the deal (Login Request Initiation)

The Smuggler (SPA) creates:

A split note (code_challenge derived from code_verifier)
A *serial number (SHA-256 logic used to generate it)

He sends:

One half of the split note (code_challenge)
Along with the request via the courier (HTTP request)

to the Boss (Authorization Server).

2. Boss stores and redirects (Authorization Request Step)

The Boss (Authorization Server):

Receives the split note (code_challenge)
Stores it temporarily along with the serial number logic (SHA-256)

He then redirects the Smuggler (SPA) to log in and verify identity.

The Cartel (User Database) validates the Smuggler’s credentials.

3. Boss issues pickup code (Authorization Code Issued)

Once the Smuggler (SPA) is successfully authenticated:

The Boss (Authorization Server):

Issues a pickup code (authorization_code)
Redirects the Smuggler to the designated place to receive the money (frontend callback URL

4. Smuggler sends proof (Token Request Step)

The Smuggler (SPA) now sends another request to the Boss with:

The pickup code (authorization_code)
The other half of the split note (code_verifier)

via the courier (HTTP request)

5. Boss verifies and releases cash (Token Exchange)

The Boss (Authorization Server) now:

  • Merges the two halves of the split note and verifies the serial number
  • Encrypts the received code_verifier using SHA-256
  • Generates a code_challenge from it and compares it with the previously stored code_challenge

✅ If they match, the Boss releases the cash (access_token)

🎯 Why This Flow is Secure

Even if an attacker intercepts the pickup code (authorization_code), they cannot get the cash (access_token) without the other half of the split note (code_verifier).

👉 This ensures that only the original Smuggler (SPA) who initiated the request can complete the process

🔐 OAuth 2.1 PKCE Flow (Technical Overview)

PKCE Flow Diagram

PKCE Flow Diagram

Step-by-Step Technical Flow

1. SPA generates PKCE parameters
The SPA (Frontend Application) generates a random code_verifier and derives a code_challenge using a method (typically S256 = SHA-256). It then sends the code_challenge and method to the Authorization Server.

2. Authorization Server stores challenge and prompts login
The Authorization Server stores the code_challenge (along with the method) temporarily, linked to the authorization request. It then displays the login page to the user.

3. User authenticates and receives authorization code
After successful login, the Authorization Server redirects back to the SPA with an authorization code: http://{spa}/callback?code=AUTH_CODE

Note: This authorization_code is internally mapped to the stored code_challenge.

4. SPA exchanges code for tokens
The SPA sends the following to the token endpoint (/oauth/token):

authorization_code
code_verifier

5. Authorization Server verifies and issues tokens The Authorization Server:

  1. Hashes the received code_verifier using the same method (S256)
  2. Compares it with the stored code_challenge

✅ If they match, the server issues the tokens (e.g., access_token, optionally refresh_token)

⚡ Key Takeaway PKCE ensures that even if the authorization_code is intercepted, it cannot be exchanged for tokens without the original code_verifier.

Security Takeaways

PKCE is essential for securing SPAs. Since secrets cannot be safely stored in the frontend, PKCE ensures that only the original client can exchange the authorization code for tokens.

If you are using OAuth in your frontend application, implementing PKCE is a must

Top comments (0)