🔑Key Takeaway

A developer-focused guide to implementing OAuth 2.0 PKCE for browser and mobile apps, starting from the threat model that made PKCE necessary.

OAuth 2.0 PKCE for Browser and Mobile Apps: The Threat-Model-First Setup

A developer-focused guide to implementing OAuth 2.0 PKCE for browser and mobile apps, starting from the threat model that made PKCE necessary.

B
Blog-Ghar EditorialAuthor
3 September 2026Published
5 min959 words
26Views

OAuth 2.0 was originally designed with the assumption that the client application could keep a secret — a client_secret known only to the client and the authorization server. This assumption works well for server-side web applications where the secret can be stored securely on the backend. However, browser-based applications, single-page applications (SPAs), and mobile applications cannot reliably keep a secret. The source code of a JavaScript application running in a browser is visible to anyone who opens the developer tools. A compiled mobile application can be decompiled to reveal embedded secrets. Any secret embedded in a client-side application is accessible to an attacker.

This limitation creates a security vulnerability in the standard OAuth 2.0 Authorization Code flow when used with public clients. In the standard flow, the authorization server issues an authorization code that the client exchanges for an access token using its clientsecret. If an attacker intercepts the authorization code (through a man-in-the-middle attack, a malicious browser extension, or a compromised redirect URI), they cannot exchange it for an access token without the clientsecret. This is the security property that makes the Authorization Code flow secure for confidential clients.

However, for public clients (browser and mobile apps) that cannot keep a secret, intercepting the authorization code is sufficient to obtain an access token. The attacker simply exchanges the intercepted code directly with the authorization server, bypassing the need for the client_secret entirely. This attack is known as the authorization code interception attack, and it was formally described in RFC 7636 as the primary threat that PKCE addresses.

Understanding the PKCE Mechanism

Proof Key for Code Exchange (PKCE, pronounced "pixy") is an extension to OAuth 2.0 that provides a secure authorization flow for public clients. PKCE was originally developed for native mobile applications but has become the recommended approach for browser-based and single-page applications as well.

The PKCE mechanism adds two cryptographic values to the authorization request: the codeverifier and the codechallenge. The codeverifier is a high-entropy cryptographic random string generated by the client before the authorization request begins. The codechallenge is derived from the code_verifier using a one-way transformation (SHA-256 hashing).

When the client initiates the authorization request, it includes the codechallenge and the method used to derive it. The authorization server stores the codechallenge and the method, associating them with the authorization code that it will issue. When the client later exchanges the authorization code for an access token, it includes the codeverifier. The authorization server computes the codechallenge from the codeverifier using the same method and compares it with the stored codechallenge. If the values match, the authorization server knows that the client making the token request is the same client that initiated the authorization request, and it issues the access token.

The critical security property of PKCE is that an attacker who intercepts the authorization code cannot exchange it for an access token. To do so, the attacker would need to compute a codeverifier that produces the stored codechallenge. However, because the transformation is one-way (SHA-256), the attacker cannot compute the original codeverifier from the codechallenge. Without the code_verifier, the token exchange fails.

Implementing PKCE in React Native

React Native applications should use the AppAuth library, which provides a well-tested, standards-compliant implementation of the OAuth 2.0 and PKCE flow. AppAuth supports both iOS and Android and handles the complex cryptographic operations and token management that PKCE requires.

The implementation starts by configuring the authorization service configuration with the issuer URL, authorization endpoint, token endpoint, and other required parameters. The authorization service configuration tells the AppAuth library how to communicate with the specific OAuth 2.0 provider you are using.

The authorization request is then constructed with the required scopes, the redirect URI (which must be registered with the provider), and additional parameters. The AppAuth library automatically generates the codeverifier and codechallenge when you set the codeChallengeMethod to S256.

After the user completes the authorization in the system browser, the redirect URI is called with the authorization code. Your application intercepts this redirect and exchanges the authorization code for tokens using the token endpoint. The AppAuth library automatically includes the code_verifier in the token request.

The resulting tokens (access token, refresh token, and ID token if using OpenID Connect) are stored securely. On iOS, tokens should be stored in the Keychain. On Android, tokens should be stored in the Encrypted SharedPreferences. Never store tokens in AsyncStorage, localStorage, or any unencrypted storage mechanism.

Common PKCE Vulnerabilities and How to Avoid Them

Embedding clientid in the application: Some developers treat the clientid as a secret and attempt to hide it using code obfuscation or native code. The clientid is not a secret in OAuth 2.0 PKCE — it is a public identifier. However, embedding it in the application is not the primary vulnerability. The vulnerability is when clientsecret is also embedded, which defeats the purpose of PKCE.

Using weak codeverifier values: The PKCE specification requires the codeverifier to be a high-entropy cryptographic random string with a minimum length of 43 characters and a maximum length of 128 characters, using the characters A-Z, a-z, 0-9, "-", ".", "_", and "~". Using a shorter or lower-entropy verifier reduces the security of the PKCE mechanism.

Not validating the state parameter: The state parameter is a critical anti-forgery mechanism in OAuth 2.0. Always generate a random state value before initiating the authorization request, store it securely, and validate it when the authorization response is received. Failing to validate the state parameter enables cross-site request forgery attacks.

Using the wrong redirect URI: The redirect URI registered with the authorization server must match exactly with the redirect URI used in the authorization request. Using a different redirect URI in the token request will cause the token exchange to fail and may indicate an attempted attack.

B

Written by Blog-Ghar Editorial

Passionate about sharing knowledge and insights on technology, lifestyle, and more. Follow for more curated content delivered to your inbox.

1k+ words published
Top contributor

Comments (0)

Please log in to leave a comment.

Loading comments...