This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Configuring Proof Key for Code Exchange (PKCE) between AM 2.0 and Okta

How to configure PKCE between Access Management 2.0 and an Okta OIDC Application

    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_verifier in the token request matches the previously submitted code_challenge.


    Which One is Generated First?

    code_verifier is generated first

    • It is the original, client-generated secret.
    • The code_challenge is derived from the code_verifier using a transformation algorithm (usually SHA-256 and base64url encoding).

    Sequence

    1. Generate code_verifier (random 43–128 character string)
    2. Derive code_challenge from the code_verifier
    3. Send code_challenge in the /authorize request
    4. Later, send code_verifier in the /token request 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

    1. Login to Okta Admin Console

    2. Go to Applications → Create App Integration

    3. Choose:

      • Sign-in method: OIDC – OpenID Connect
      • Application type: Native Application (or Web if backend app)
    4. Click Next

    5. Fill in:

      • App name
      • Sign-in redirect URIs: You application callback URI (eg https://www.getpostman.com/oauth2/callback)
      • Sign-out redirect URIs (optional)
    6. Click Save

    Settings Behind the Scenes

    • Grant type: authorization_code

    • PKCE is enabled automatically for native apps

    • No client secret required (for public/native apps)

    • Okta’s .well-known/openid-configuration will 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:

    FieldValue
    Aliasokta
    Authorization URLhttps://<your_okta_domain>/oauth2/default/v1/authorize
    Token URLhttps://<your_okta_domain>/oauth2/default/v1/token
    User Info URLhttps://<your_okta_domain>/oauth2/default/v1/userinfo
    Logout URL(optional, for federated logout)
    Client IDFrom Okta
    Client Secret(Leave blank for public client / PKCE only)
    Default Scopesopenid profile email
    Use JWK URL✅ Enabled
    JWK URLhttps://<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_challenge parameter in the /authorize request

    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_challenge logic if necessary via SPI or reverse proxy

    Summary Table

    StepOkta OIDC AppAccess Management IdP (Okta)
    App TypeNative (no secret)OIDC Identity Provider
    PKCE UsageAutomatic for native appsMust support code_challenge if Okta requires it
    Grant TypeAuthorization Code + PKCEAuthorization Code
    Client SecretNot requiredOptional (only if confidential client)
    Redirect URIMust match in both Okta and Access ManagementAccess Management’s broker URL

    Visual Flow

    References


    Author

    • Jim Knupp:Director, Application Security, ActivePlatform™, R&D._