PKCE

Proof Key for Code Exchange (PKCE, RFC 7636) is an extension to the OAuth 2.0 Authorization Code Flow that prevents authorization code interception attacks. PKCE is required by OAuth 2.1 guidance and is strongly recommended for all clients, especially mobile and single-page applications.

PKCE can be used with or without a client secret. Mobile and other public clients can safely perform the flow without a client secret because PKCE ensures only the app instance that initiated the request can complete the token exchange.

How PKCE works

PKCE adds a dynamically created cryptographic secret to the standard authorization code flow. Before each authorization request, your application generates a random code_verifier and derives a code_challenge from it. The challenge is sent with the authorization request, and the original verifier is sent with the token exchange, allowing ID.me to verify both came from the same client.

Prerequisites

Before implementing PKCE, ensure you have:

  • A registered ID.me application with a client_id
  • One or more configured redirect_uri values
  • Access to the appropriate environment (Sandbox or Production)
Tip

Most OAuth/OIDC client libraries handle PKCE automatically. Check your library’s documentation before implementing the steps below manually.

Step-by-step implementation

1

Retrieve OIDC discovery document

Fetch the discovery document to get all endpoint URLs dynamically.

EnvironmentURL
Sandboxhttps://api.idmelabs.com/oidc/.well-known/openid-configuration
Productionhttps://api.id.me/oidc/.well-known/openid-configuration
2

Generate PKCE pair

Generate a random code_verifier — a 43–128 character URL-safe string. Then derive the code_challenge by computing the SHA-256 hash of the verifier and Base64-URL encoding the result without padding. Store the code_verifier securely for use during the token exchange in step 6.

3

Send authorization request

Redirect the user to the ID.me authorization endpoint. Include the standard OIDC parameters along with the two PKCE-specific parameters.

Parameters

ParameterDescription
client_idYour application’s client identifier
redirect_uriYour registered redirect URI
response_typeMust be code
scopeMust include openid plus your policy scope
nonceA random value generated per request
stateA random value tied to this session for CSRF protection
code_challengeThe SHA-256 hash of your code_verifier, Base64-URL encoded
code_challenge_methodMust be S256
4

User verifies identity

The user is redirected to ID.me to authenticate and complete identity verification. No action is required from your application during this step.

5

Receive authorization code

ID.me redirects the user back to your redirect_uri with an authorization code and the state value appended as query parameters.

Critical

Always verify that the returned state matches the value you sent in the authorization request before proceeding. This prevents CSRF attacks.

6

Exchange code for tokens

Send a POST request to ID.me’s token endpoint with the code_verifier to complete the exchange. ID.me verifies that the code_verifier matches the code_challenge sent in step 3, confirming the request originated from the same client.

  • Endpoint: https://api.id.me/oauth/token
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded

Parameters

ParameterDescription
grant_typeMust be authorization_code
codeThe authorization code from the callback
client_idYour application’s client identifier
redirect_uriMust match the value used in the authorization request
code_verifierThe original code_verifier generated in step 2
client_secretOptional; include if your application can store it securely

The response includes an access_token, refresh_token, and an id_token (a signed JWT containing user claims).

7

Get user attributes

Send a GET request to the UserInfo endpoint with the access token to retrieve user attributes.

  • Endpoint: https://api.id.me/api/public/v3/userinfo
  • Method: GET
  • Authorization: Bearer {access_token}

For details on validating and decoding the ID token, see Integration.

PKCE for mobile applications

PKCE is especially important for mobile clients where the client secret cannot be stored securely. Because PKCE ensures that only the same app instance that initiated the login request can complete the token exchange — even if the authorization code is intercepted — mobile and other public clients can safely perform the flow without a client secret.

For mobile-specific implementation details, see the Mobile SDK documentation.

When using PKCE without a client secret, omit the client_secret parameter from the token exchange request. The code_verifier provides the necessary proof of identity.