I need to implement OAuth2 PKCE (Proof Key for Code Exchange) authentication flow in my React Native app. Can someone show me working code examples for generating the code verifier, code challenge, and handling the authorization callback? I want to see real implementation examples.
Great question! PKCE is definitely the right approach for React Native apps since you can't securely store client secrets on mobile devices. Let me walk you through a practical implementation.
First, you'll need to generate the code verifier and challenge. Here's a solid approach:
import crypto from 'react-native-crypto';
import { Base64 } from 'js-base64';
// Generate random code verifier (43-128 characters)
const generateCodeVerifier = () => {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Base64.fromUint8Array(array)
.replace(/+/g, '-')
.replace(///g, '_')
.replace(/=/g, '');
};
// Generate code challenge from verifier
const generateCodeChallenge = async (verifier) => {
const digest = await crypto.subtle.digest('SHA-256',
new TextEncoder().encode(verifier)
);
return Base64.fromUint8Array(new Uint8Array(digest))
.replace(/+/g, '-')
.replace(///g, '_')
.replace(/=/g, '');
};
For handling the authorization flow, I'd recommend using react-native-app-auth or expo-auth-session if you're using Expo—they handle a lot of the complexity for you. But if you're doing it manually, here's the flow:
// 1. Generate verifier and challenge
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);
// 2. Store verifier securely (use react-native-keychain)
await Keychain.setGenericPassword('oauth_verifier', codeVerifier);
// 3. Build authorization URL
const authUrl = ` https://your-oauth-provider.com/authorize?` +
`client_id=${CLIENT_ID}&` +
`redirect_uri=${REDIRECT_URI}&` +
`response_type=code&` +
`scope=openid%20profile&` +
`code_challenge=${codeChallenge}&` +
`code_challenge_method=S256`;
// 4. Open browser and handle redirect
const result = await Linking.openURL(authUrl);
For the callback handling, set up a deep link listener to capture the authorization code:
// Handle the redirect
Linking.addEventListener('url', async ({ url }) => {
const code = new URL(url).searchParams.get('code');
if (code) {
// Retrieve stored verifier
const credentials = await Keychain.getGenericPassword();
const codeVerifier = credentials.password;
// Exchange code for token
const tokenResponse = await fetch('https://your-oauth-provider.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: CLIENT_ID,
code: code,
redirect_uri: REDIRECT_URI,
code_verifier: codeVerifier
})
});
const tokens = await tokenResponse.json();
// Store tokens securely and you're done!
}
});
A few important tips: Always store the code verifier in secure storage (Keychain on iOS, Keystore on Android) before opening the browser. Make sure your redirect URI is properly configured in your app's linking configuration. Also, consider adding state parameter for additional security against CSRF attacks.
Are you building this from scratch, or are you considering using a pre-built library? What OAuth provider are you integrating with?