> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.id.me/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.id.me/_mcp/server.

# PKCE

> Implement OAuth 2.0 Authorization Code Flow with PKCE for secure identity verification using IDMe.

---

Proof Key for Code Exchange (PKCE, [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)) is an extension to the OAuth 2.0 Authorization Code Flow that prevents authorization code interception attacks. PKCE is required by [OAuth 2.1](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1) guidance and is strongly recommended for all clients, especially mobile and single-page applications.

> **Info**
>
> 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.

> **Note**
>
> This guide covers **OAuth 2.0** Authorization Code with PKCE. The flow issues an access token that can be used to retrieve user attributes from the IDMe Attributes API. If your application also needs an `id_token` (a signed JWT with identity claims) or requires standard OIDC discovery, see the [OIDC PKCE guide](/guides/oidc/pkce) instead.

## 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 IDMe to verify both came from the same client.

## OAuth 2.0 + PKCE Data Flow

## Prerequisites

Before implementing PKCE, ensure you have:

* A registered IDMe application with a `client_id`
* One or more configured `redirect_uri` values
* The OAuth 2.0 scopes your application requires
* Access to the appropriate environment (Sandbox or Production)

> **Tip**
>
> Most OAuth 2.0 client libraries handle PKCE automatically. Check your library's documentation before implementing the steps below manually.

## Step-by-step implementation

#### Discover endpoint URLs

Fetch the OpenID Connect discovery document to get all endpoint URLs dynamically. This document covers both OAuth 2.0 and OIDC flows and exposes `authorization_endpoint`, `token_endpoint`, `code_challenge_methods_supported`, and other configuration fields.

| Environment | URL                                                              |
| ----------- | ---------------------------------------------------------------- |
| Sandbox     | `https://api.idmelabs.com/oidc/.well-known/openid-configuration` |
| Production  | `https://api.id.me/oidc/.well-known/openid-configuration`        |

#### 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 5.

#### Send authorization request

Redirect the user to the IDMe authorization endpoint. Include your application parameters along with the two PKCE-specific parameters.

#### Parameters

| Parameter               | Description                                                     |
| ----------------------- | --------------------------------------------------------------- |
| `client_id`             | Your application's client identifier                            |
| `redirect_uri`          | Your registered redirect URI                                    |
| `response_type`         | Must be `code`                                                  |
| `scope`                 | Space-separated list of OAuth 2.0 scopes your application needs |
| `state`                 | A random value tied to this session for CSRF protection         |
| `code_challenge`        | The SHA-256 hash of your `code_verifier`, Base64-URL encoded    |
| `code_challenge_method` | Must be `S256`                                                  |

> **Note**
>
> Unlike the OIDC flow, a `nonce` parameter is not used here because no `id_token` is issued. If your application requires identity claims, use the [OIDC PKCE flow](/guides/oidc/pkce) which includes `openid` in the scope and returns an `id_token`.

#### User authorizes access

The user is redirected to IDMe to authenticate and grant your application the requested scopes. No action is required from your application during this step.

#### Receive authorization code

IDMe 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.

#### Exchange code for tokens

Send a POST request to IDMe's token endpoint with the `code_verifier` to complete the exchange. IDMe 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

| Parameter       | Description                                                 |
| --------------- | ----------------------------------------------------------- |
| `grant_type`    | Must be `authorization_code`                                |
| `code`          | The authorization code from the callback                    |
| `client_id`     | Your application's client identifier                        |
| `redirect_uri`  | Must match the value used in the authorization request      |
| `code_verifier` | The original `code_verifier` generated in step 2            |
| `client_secret` | Optional; include if your application can store it securely |

#### Token response

A successful response returns a JSON object containing:

| Field           | Description                                                      |
| --------------- | ---------------------------------------------------------------- |
| `access_token`  | Bearer token used to authenticate requests to IDMe APIs          |
| `token_type`    | Always `Bearer`                                                  |
| `expires_in`    | Lifetime of the access token in seconds                          |
| `refresh_token` | Token used to obtain a new access token without user interaction |
| `scope`         | The scopes actually granted (may differ from those requested)    |

#### Retrieve user attributes

Send a GET request to the IDMe Attributes API with the access token to retrieve the verified user attributes granted by the requested scopes.

* **Endpoint**: `https://api.id.me/api/public/v3/attributes.json`
* **Method**: `GET`
* **Authorization**: `Bearer {access_token}`

The response is a JSON object containing an `attributes` array. Each element includes a `handle` (machine-readable key), a `name` (human-readable label), and a `value`.

**`Example`**

```json Example
{
  "attributes": [
    { "handle": "fname",       "name": "First Name",        "value": "Casey"           },
    { "handle": "lname",       "name": "Last Name",         "value": "Jones"           },
    { "handle": "email",       "name": "Email",             "value": "casey@example.com" },
    { "handle": "birth_date",  "name": "Birth Date",        "value": "1990-09-21"      },
    { "handle": "uuid",        "name": "Unique Identifier", "value": "d733a89e2e634f04" }
  ]
}
```

The attributes returned depend on the scopes your application requested and the user's verified data. If your application requires identity claims in standard OIDC format or a signed `id_token`, use the [OIDC PKCE flow](/guides/oidc/pkce) instead.

#### Refresh the access token

When the access token expires, use the `refresh_token` to obtain a new one without requiring user interaction.

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

#### Parameters

| Parameter       | Description                                        |
| --------------- | -------------------------------------------------- |
| `grant_type`    | Must be `refresh_token`                            |
| `refresh_token` | The refresh token from the previous token response |
| `client_id`     | Your application's client identifier               |
| `client_secret` | Optional; include if your application uses one     |

> **Note**
>
> Refresh tokens may be rotated on each use. Always store the new `refresh_token` returned in the response and discard the old one.

## 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](/guides/mobile-sdk/overview).

> **Note**
>
> When using PKCE without a client secret, omit the `client_secret` parameter from the token exchange and refresh requests. The `code_verifier` provides the necessary proof of identity for the initial exchange.

## OAuth 2.0 vs OIDC

IDMe supports both OAuth 2.0 and OpenID Connect. Choosing between them depends on what your application needs:

|                                           | OAuth 2.0 + PKCE | OIDC + PKCE |
| ----------------------------------------- | :--------------: | :---------: |
| Obtain access token                       |         ✓        |      ✓      |
| Refresh access token                      |         ✓        |      ✓      |
| Retrieve user attributes (Attributes API) |         ✓        |      ✓      |
| Receive `id_token` (signed JWT)           |                  |      ✓      |
| Access UserInfo endpoint (OIDC claims)    |                  |      ✓      |
| Cryptographic identity verification       |                  |      ✓      |
| Required `openid` scope                   |                  |      ✓      |

Both flows can retrieve user attributes, but through different endpoints and in different formats. OAuth 2.0 returns attributes via IDMe's Attributes API (`/api/public/v3/attributes.json`) in a handle/name/value structure. OIDC returns attributes via the UserInfo endpoint in standard claims format and additionally issues a signed `id_token` for cryptographic identity verification. If you need to verify the user's identity with a signed assertion, use the OIDC flow.

## Related resources

#### [OIDC PKCE](/guides/oidc/pkce)

Authorization Code Flow with PKCE for identity verification and user attribute retrieval

#### [OIDC integration](/guides/open-id-connect/integration)

Full OIDC integration guide including token validation and payload parsing

#### [Mobile SDK](/guides/mobile-sdk/overview)

Native SDK integration for iOS and Android

#### [RFC 7636 – PKCE](https://datatracker.ietf.org/doc/html/rfc7636)

The PKCE specification