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

# Integration

> Step-by-step guide to integrating IDMe's OAuth 2.0 authorization code flow into your application.

### Prerequisites

You will need an [IDMe developer account](https://api.id.me/en/session/new) to obtain the following:

* Client ID
* Client Secret
* Redirect URI

## Direct users to authorization endpoint

To begin the OAuth flow, your client application must direct the user to the IDMe authorization endpoint. There, the user signs in to IDMe and is prompted to grant or deny access to your application.

#### Authorization endpoint

**`Example`**

```html Example
https://api.id.me/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=optional&eid=FOO-bar-123
```

**`Groups`**

```html Groups
https://groups.id.me/?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=optional&eid=FOO-bar-123

```

**`PKCE`**

```html PKCE
https://api.id.me/oauth/authorize?client_id=...&redirect_uri=...&response_type=code&scope=...&state=...&code_challenge=CODE_CHALLENGE&code_challenge_method=S256
```

> **Important**
>
> Replace the `CLIENT_ID`, `REDIRECT_URI`, and `SCOPE` with your inputs

#### Parameters

| Name                  | Description                                                                                                                                                                            | Supported values                                                       |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| client_id             | The client identifier received during app registration. It is automatically generated and located in your application dashboard                                                        |                                                                        |
| scope                 | A parameter that defines the policy you are requesting permission to access                                                                                                            | [View full list](/integrations/configurations/configuration-standards) |
| redirect_uri          | Where the user gets redirected after authorizing an app. Set by the developer within the application dashboard.                                                                        |                                                                        |
| response_type         | Determines the authorization type                                                                                                                                                      | code                                                                   |
| state                 | An optional parameter to carry through any server-specific state you need to, for example, protect against CSRF issues. This param will be passed back to your redirect URI untouched. |                                                                        |
| op                    | An optional param that triggers                                                                                                                                                        | signin, signup                                                         |
| eid                   | An optional parameter to carry through any external identifiers you want returned in the payload response                                                                              |                                                                        |
| code_challenge        | PKCE challenge                                                                                                                                                                         |                                                                        |
| code_challenge_method | Challenge method                                                                                                                                                                       | S256                                                                   |

#### Optional IDMe widget

**`Widget`**

```html Widget
<span
  id='idme-wallet-button'
  data-scope='SCOPE'
  data-client-id='CLIENT_ID'
  data-redirect='REDIRECT_URI'
  data-response='code'>
</span>
<script src='https://s3.amazonaws.com/idme/developer/idme-buttons/assets/js/idme-wallet-button.js'></script>
```

## Receive the authorization code

Once the user completes the authorization process on IDMe, they will be redirected to your `redirect_uri` with the authorization code parameter appended.

**`Redirect URI with code example`**

```html Redirect URI with code example
https://example.com/callback?code=488e864b
```

## Exchange authorization code for access token

After the user authorizes your application, exchange the authorization code for an `access_token` and `refresh_token` by sending a request to IDMe's token endpoint.
The response payload includes both tokens and their expiration times.

* **Endpoint**: `https://api.id.me/oauth/token`
* **Method**: `POST`
* **Response type**: application/JSON

#### Parameters

| Name          | Description                                                                                                                      |
| ------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| code          | The authorization code that you received in the previous step                                                                    |
| client_id     | The client identifier received during app registration. It is automatically generated and located in your application dashboard. |
| client_secret | A secret identifier received during app registration. It is automatically generated and located in your application dashboard.   |
| redirect_uri  | Where the user is redirected after authorizing an app. Set by the developer within the application dashboard.                    |
| grant_type    | The only supported value is `authorization_code`                                                                                 |
| code_verifier | PKCE verifier used to complete the code exchange (required when PKCE is used)                                                    |

**`Example`**

```html Example
curl -X POST -d 
"code=488e864b&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&redirect_uri=REDIRECT_URI&grant_type=authorization_code" 
https://api.id.me/oauth/token
```

**`PKCE`**

```html PKCE
curl -X POST https://api.id.me/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=AUTHORIZATION_CODE" \
  -d "client_id=CLIENT_ID" \
  -d "client_secret=CLIENT_SECRET" \
  -d "redirect_uri=REDIRECT_URI" \
  -d "code_verifier=CODE_VERIFIER"
```

> **Important**
>
> Replace the `CLIENT_ID`, `REDIRECT_URI`, and `SCOPE` with your inputs

## Obtain access token

#### Parameters

| Name               | Description                                                                                                  |
| ------------------ | ------------------------------------------------------------------------------------------------------------ |
| access_token       | Included with every API request so that IDMe can verify your application's authorization to access user data |
| token_type         | Represents how an `access_token` will be generated and presented for resource access calls                   |
| expires_in         | Describes the lifetime of the `access_token` in seconds                                                      |
| refresh_token      | Contains the information required to obtain a new `access_token`                                             |
| refresh_expires_in | Describes the lifetime of the `refresh_token` in seconds                                                     |
| scope              | Defines the policy you are requesting permission to access                                                   |

**`Example payload`**

```json Example payload
{
  "access_token" : "a0b1c2d3f4g5h6i7j8k9l0m1n2o3p4q5",
  "token_type" : "bearer",
  "expires_in" : "300",
  "refresh_token" : "e7c77fe1fd5ece9aaccb129f6dd39431",
  "refresh_expires_in" : "604800",
  "scope" : "military"
}
```

## Exchange access token for user data

To retrieve user data, make an HTTP GET request to the protected endpoint below. Include the `access_token` in the request. IDMe will validate the token to ensure it's valid and has the required scope.

* **Endpoint**: `https://api.id.me/api/public/v3/attributes.json`
* **Method**: `GET`
* **Response type**: application/JSON

#### Parameters

| Name         | Description                                                                                                          |
| ------------ | -------------------------------------------------------------------------------------------------------------------- |
| access_token | A token included with each API call that allows IDMe to verify your application's authorization                      |
| callback     | If your AJAX application requires a JSON response, include a callback parameter in the API call to wrap the response |

**`Example payload`**

```json Example payload
{
  "attributes": [
    {
      "handle": "fname",
      "name": "First Name",
      "value": "Sean"
    },
    {
      "handle": "lname",
      "name": "Last Name",
      "value": "Moen"
    },
    {
      "handle": "email",
      "name": "Email",
      "value": "sean.moen@id.me"
    },
    {
      "handle": "uuid",
      "name": "Unique Identifier",
      "value": "d733a89e2e634f04ac2fe66c97f71612"
    },
    {
      "handle": "zip",
      "name": "Postal Code",
      "value": "44058-1478"
    },
    {
      "handle": "identifier",
      "name": "External Identifier",
      "value": "FOO-bar-123"
    }
  ],
  "status": [
    {
      "group": "military",
      "subgroups": [
        "Service Member"
      ],
      "verified": true
    }
  ]
}
```

## Parse the JSON response

Properly parsing the JSON response is essential for building a scalable integration. How your application handles the response
determines whether it can gracefully support future changes, such as the addition of new attributes, without breaking.

> **Best practice**
>
> * Use object handles to index attribute values
> * Validate only attributes that are currently returned
> * Store raw JSON responses for auditing and debugging
> * Create a database table to store verification status, UUID, and authoritative data from the IDMe API
> * Use the `uuid` as a foreign key to link IDMe user activity across your application
> * Pre-fill form fields to streamline the post-verification user experience

#### Example data types

The attribute type determines what data type will be returned from IDMe's REST API. The following data types are expected from IDMe's REST API:

**`String`**

```json String
{
  "handle": "email",
  "name": "Email",
  "value": "testing@id.me"
}
```

**`Integer`**

```json Integer
{
  "handle": "age",
  "name": "Age",
  "value": 21
}
```

**`Array`**

```json Array
{
    "handle": "covid_vaccine_records",
    "name": "Covid Vaccine Records",
    "value": [
      {
          "brand": "Pfizer",
          "date": "2022-01-01T00:00:00-05:00",
          "type": "primary"
      },
      {
          "brand": "Pfizer",
          "date": "2022-02-02T00:00:00-05:00",
          "type": "primary"
      }
  ]
}
```

**`Object`**

```json Object
{
  "handle": "previous_addresses",
  "name": "Previous address(es) if available",
  "value": [
      {
          "normalized_street": "8281 Greensboro Drive",
          "street1": "8281 Greensboro Drive",
          "street2": "",
          "city": "West McLean",
          "state": "VA",
          "province": "",
          "zip": "22102",
          "country": "US",
          "normalized": "false",
          "primary": "false"
      },
      {
          "normalized_street": "6647 WILDFLOWER DR S",
          "street1": "6647 WILDFLOWER DR S",
          "street2": "",
          "city": "COTTAGE GROVE",
          "state": "MN",
          "province": "",
          "zip": "55016",
          "country": "US",
          "normalized": "false",
          "primary": "false"
      }
  ]
}
```

> **Important**
>
> **Do NOT** expect all attribute values to be a string