DEV Community

Cover image for OAuth2 and PKCE: Enhancing Security for Public Clients
Igor Venturelli
Igor Venturelli

Posted on • Originally published at igventurelli.io

OAuth2 and PKCE: Enhancing Security for Public Clients

PKCE strengthens OAuth2 by thwarting code interception attacks. Learn why it’s essential and how to implement it in your apps securely

OAuth 2.0 revolutionized application authorization, providing a robust framework for granting limited access to resources without sharing credentials. However, its widespread adoption revealed significant vulnerabilities, particularly for public clients such as single-page applications or mobile apps that cannot securely store a client_secret. This is where PKCE (Proof Key for Code Exchange) steps in, addressing these weaknesses and fortifying the Authorization Code flow.

PKCE (pronounced "pixy") is an OAuth 2.0 extension introduced in RFC 7636. Originally designed for public clients, PKCE is now recommended for both public and confidential clients, adding an additional layer of security to the authorization process.

Why PKCE Matters: Tackling OAuth2 Vulnerabilities

In a traditional Authorization Code flow, an attacker can intercept the code during its transmission from the authorization server to the client. This is particularly problematic for public clients, which lack the means to securely handle a client_secret. Without PKCE, this vulnerability exposes applications to authorization code interception attacks, allowing attackers to exchange the stolen code for an access token.

PKCE mitigates this risk by binding the authorization request with the token exchange process using a dynamically generated secret. This ensures that even if the code is intercepted, it cannot be successfully exchanged without the original proof key.

How PKCE Works: The Key Parameters

PKCE introduces three critical parameters to the Authorization Code flow:

  • code_verifier: A high-entropy cryptographic random string, generated by the client. This is the "proof key."
  • code_challenge: A derived value of the code_verifier that is sent with the authorization request.
  • code_challenge_method: Specifies the method used to derive the code_challenge from the code_verifier. The RFC supports two methods:
    • plain: The code_challenge is the same as the code_verifier.
    • S256: A SHA-256 hash of the code_verifier, Base64 URL-encoded. This is the preferred and more secure method.

Understanding the S256 Method

The S256 method enhances security by hashing the code_verifier before transmission. Here's how it works:

  1. Compute the SHA-256 hash of the code_verifier.
  2. Base64 URL-encode the hash.
  3. Send the resulting code_challenge to the authorization server.

For example, in Java:

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

public class PKCEExample {

    public static void main(String[] args) throws Exception {
        String codeVerifier = "randomlyGeneratedCodeVerifier";
        String codeChallenge = generateCodeChallenge(codeVerifier);
        System.out.println("Code Verifier: " + codeVerifier);
        System.out.println("Code Challenge: " + codeChallenge);
    }

    public static String generateCodeChallenge(String codeVerifier) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hashedBytes = digest.digest(codeVerifier.getBytes(StandardCharsets.US_ASCII));
        return Base64.getUrlEncoder().withoutPadding().encodeToString(hashedBytes);
    }
}
Enter fullscreen mode Exit fullscreen mode

Output:

Image description

This ensures that even if the code_challenge is intercepted, the code_verifier is required to complete the flow.

The PKCE-Augmented Flow

The PKCE-enhanced Authorization Code flow mirrors the regular flow but includes the code_challenge (and optionally code_challange_method) during the initial request and the code_verifier during the token exchange. This dynamic binding ensures that only the original client, with the correct proof key, can successfully exchange the authorization code.

Conclusion

PKCE is a simple yet powerful enhancement to the OAuth 2.0 Authorization Code flow. By adding a dynamically generated proof key, it neutralizes authorization code interception attacks, making OAuth 2.0 significantly more secure. Its adoption is now recommended for all OAuth clients, both public and confidential, reflecting its critical role in modern application security.


Let’s connect!

📧 Don’t Miss a Post! Subscribe to my Newsletter!
➡️ LinkedIn
🚩 Original Post

Top comments (0)