Objective
In today’s security-conscious digital landscape, safeguarding user authentication flows against interception and unauthorized token exchange is critical, especially when integrating with public or external Identity Providers. Proof Key for Code Exchange (PKCE) is an extension to the OAuth 2.0 Authorization Code Flow that adds a layer of security to mitigate the risk of code interception attacks.
This document provides a structured overview of PKCE: its definition, purpose, and practical value and follows with a comprehensive, step-by-step guide to:
- ✅ Understand how PKCE strengthens the OAuth2/OIDC flow,
- ✅ Configure Access Management 2.0 as an Identity Broker that delegates authentication to an external Identity Provider, and
- ✅ Integrate Okta as a secure and standards-compliant OIDC Identity Provider using PKCE.
This guide is intended for architects, developers, and system administrators seeking to enable secure OIDC federation between Access Management 2.0 and Okta in environments where PKCE is required.
Whether you’re developing public web clients, mobile applications, or federated authentication systems, implementing PKCE ensures that your Authorization Code Flow adheres to best practices in secure identity delegation.
Purpose of PKCE (Proof Key for Code Exchange)
Originally designed for mobile/native clients, PKCE (RFC 7636) prevents authorization code interception attacks in OAuth2/OIDC Authorization Code Flow.
Why is it needed?
In the traditional Authorization Code Grant, the client app receives the authorization code in a browser redirect, which could be intercepted by malicious apps (especially in public clients like SPA or mobile apps).
PKCE ensures that:
- The authorization code is bound to the client application through a challenge
- Even if an attacker steals the code, they cannot exchange it for a token without the original code verifier
PKCE Definitions
code_verifier
Definition: A high-entropy cryptographic random string used to bind the authorization request to the token request.
Format Requirements (from RFC 7636):
- Minimum length: 43 characters
- Maximum length: 128 characters
- Characters:
[A-Z],[a-z],[0-9],-,.,_,~
Purpose: Sent only in the token request. It proves that the token requester is the same party who initiated the authorization request.
code_challenge
Definition: A hashed and base64-url-encoded version of the
code_verifier, which is sent in the initial authorization request.Generation:
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier)) code_challenge_method = "S256"(Alternatively, the method can be
"plain"but"S256"is recommended for security.)Purpose: Sent in the authorization request to the authorization server, so the server can later verify that the
code_verifierin the token request matches the previously submittedcode_challenge.
Which One is Generated First?
✅ code_verifier is generated first
- It is the original, client-generated secret.
- The
code_challengeis derived from thecode_verifierusing a transformation algorithm (usually SHA-256 and base64url encoding).
Sequence
- Generate
code_verifier(random 43–128 character string) - Derive
code_challengefrom thecode_verifier - Send
code_challengein the/authorizerequest - Later, send
code_verifierin the/tokenrequest to prove the client’s identity
Example
code_verifier: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
code_challenge: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
code_challenge_method: S256
PKCE Flow: Step-by-Step
Step 1: Client creates a code verifier
code_verifier = base64url(32-96 random bytes)
Step 2: Client derives a code challenge
code_challenge = BASE64URL-ENCODE(SHA256(code_verifier))
method = S256
Step 3: Client initiates authorization request
GET /authorize?
response_type=code
client_id=CLIENT_ID
redirect_uri=REDIRECT_URI
code_challenge=CODE_CHALLENGE
code_challenge_method=S256
Step 4: Authorization server authenticates user and issues code
Step 5: Client sends token request with the code_verifier
POST /token
grant_type=authorization_code
code=AUTH_CODE
redirect_uri=REDIRECT_URI
client_id=CLIENT_ID
code_verifier=CODE_VERIFIER
Step 6: Server validates:
SHA256(code_verifier) == code_challenge ?
If yes → returns access_token, id_token, and optionally refresh_token.
Okta OIDC App Configuration with PKCE
Prerequisite
- You must use Authorization Code Flow with PKCE
- Do not require a
client_secret(suitable for public clients)
Okta App Configuration Steps
Login to Okta Admin Console
Go to Applications → Create App Integration
Choose:
- Sign-in method: OIDC – OpenID Connect
- Application type: Native Application (or Web if backend app)
Click Next
Fill in:
- App name
- Sign-in redirect URIs: You application callback URI (eg
https://www.getpostman.com/oauth2/callback) - Sign-out redirect URIs (optional)
Click Save
Settings Behind the Scenes
Grant type:
authorization_codePKCE is enabled automatically for native apps
No client secret required (for public/native apps)
Okta’s
.well-known/openid-configurationwill contain:"code_challenge_methods_supported": ["S256"]
Configure Access Management to Use Okta as OIDC Identity Provider with PKCE
To configure Access Management as a Relying Party (Client) and Okta as an OIDC Identity Provider, follow these steps:
Step 1: In Access Management Admin Console
- Go to the Realm where you want to add the external IdP
- Navigate to Identity Providers → Add Provider → OpenID Connect
Step 2: Configure OIDC IdP (Okta)
Required fields:
| Field | Value |
|---|---|
| Alias | okta |
| Authorization URL | https://<your_okta_domain>/oauth2/default/v1/authorize |
| Token URL | https://<your_okta_domain>/oauth2/default/v1/token |
| User Info URL | https://<your_okta_domain>/oauth2/default/v1/userinfo |
| Logout URL | (optional, for federated logout) |
| Client ID | From Okta |
| Client Secret | (Leave blank for public client / PKCE only) |
| Default Scopes | openid profile email |
| Use JWK URL | ✅ Enabled |
| JWK URL | https://<your_okta_domain>/oauth2/default/v1/keys |
Enable PKCE
Access Management currently does not explicitly require a checkbox to “enable PKCE” when it’s an OIDC client to another IdP
However, if the remote IdP (Okta) requires PKCE, Access Management must:
- Use the Authorization Code Flow
- Support the
code_challengeparameter in the/authorizerequest
As of recent versions, Access Management acts as a confidential client (with client_secret) for brokered OIDC IdPs. If you’re using PKCE with Okta, configure Okta to allow PKCE for confidential clients, or:
- Configure the IdP as a public client
- Add custom
code_challengelogic if necessary via SPI or reverse proxy
Summary Table
| Step | Okta OIDC App | Access Management IdP (Okta) |
|---|---|---|
| App Type | Native (no secret) | OIDC Identity Provider |
| PKCE Usage | Automatic for native apps | Must support code_challenge if Okta requires it |
| Grant Type | Authorization Code + PKCE | Authorization Code |
| Client Secret | Not required | Optional (only if confidential client) |
| Redirect URI | Must match in both Okta and Access Management | Access Management’s broker URL |
Visual Flow

References
- PKCE spec: RFC 7636
- Okta PKCE: https://developer.okta.com/docs/guides/implement-auth-code-pkce/
- Access Management Docs: [https://www.Access Management.org/docs/latest/server_admin/#openid-connect](https://www.Access Management.org/docs/latest/server_admin/#openid-connect)
Author
- Jim Knupp:Director, Application Security, ActivePlatform™, R&D._