Enforce PKCE with Auth0 Actions
This article provides a step-by-step guide to enforcing Proof Key for Code Exchange (PKCE) via post-login actions.
- Proof Key for Code Exchange (PKCE)
- Actions
- Auth0
By default, Auth0's Authorization Code Flow can operate with or without PKCE. If a code_challenge is present in the authorization request, Auth0 will validate it with a code_verifier during the token exchange. However, if code_challenge is not provided, Auth0 will proceed with the standard Authorization Code Flow unless explicitly configured to enforce PKCE for the client application strictly. This default behavior can lead to successful logins even when PKCE parameters are missing, as might be observed in testing scenarios (for example, using Postman without code_challenge). This lack of strict enforcement can be flagged as a security vulnerability during pen-tests.
To add an extra layer of security and ensure strict PKCE compliance by enforcing the presence of code_challenge for specific applications, an Auth0 Action script can be implemented. This Action will prevent login for a designated client application if the code_challenge parameter is missing from the authorization request, thereby strictly enforcing the use of PKCE.
- Navigate to
https://manage.auth0.com/. - On the Dashboard, click on Actions > Library.
- In the top right corner, click on Create Action > Build From Scratch.
- Choose the desired name, and set the Trigger to Login / Post Login.
- Use the code snippet provided below and adjust it as required.
- Deploy and add the action to the trigger.
/**
* Enforce PKCE strictly for designated SPA clients on the Authorization Code flow.
*/
exports.onExecutePostLogin = async (event, api) => {
const ENFORCED_CLIENT_IDS = ['YOUR_SPA_CLIENT_ID_1', 'YOUR_SPA_CLIENT_ID_2'];
if (!ENFORCED_CLIENT_IDS.includes(event.client.client_id)) {
return;
}
// ONLY evaluate the Authorization Code flow.
// This automatically returns early for Refresh Tokens, ROPC, Token Exchange, etc.
if (event.transaction && event.transaction.protocol !== 'oidc-basic-profile') {
return;
}
const query = event.request && event.request.query;
const codeChallenge = query && query.code_challenge;
if (!codeChallenge) {
console.warn(`Blocked login missing PKCE code_challenge for Client ID: ${event.client.client_id}`);
api.access.deny("Invalid authorization request. PKCE (code_challenge) is strictly required.");
}
};
Additional Security Hardening
To prevent bypass via less secure flows (like Implicit or Resource Owner Password Credentials), disable unnecessary Grant Types:
- Go to Applications > [the SPA].
- Scroll to Advanced Settings > Grant Types.
- Uncheck Implicit and Password.
- Ensure Authorization Code is selected.
- Ensure the Refresh Token is selected if the application is using rotating refresh tokens.