Overview

ID.me uses OpenID Connect (OIDC), built on top of OAuth 2.0 RFC6749, to authorize access to its APIs. OIDC is an open authentication protocol that enables secure user sign-in and identity data exchange. To access a user’s data, your application must include both an access_token and an id_token in requests to ID.me’s REST API. These tokens are unique to each user, must be stored securely, and the access_token expires 5 minutes after issuance.

ID.me supports both full-page redirects and popup windows for the authorization flow. After registering your application, you’ll find sample code, documentation, and options to upload your company logo and customize the button colors within the ID.me interface.

Prerequisites

ID.me developer account

To get started, create an ID.me developer account and set up your organization. This will generate your client_id and client_secret. Once your application is registered, you can configure one or more redirect_uri values to define where ID.me should return the authorization_code.

Evaluate well-known endpoints

Use the well-known endpoint to retrieve standardized configuration metadata. This JSON-formatted response includes critical details such as:

  • The issuer URL
  • Supported authentication methods
  • Token endpoint
  • Public key for verifying tokens
  • Other essential configuration settings

This metadata allows you to configure your application for secure authentication and authorization, ensuring compatibility with the OpenID Connect (OIDC) standard.

Direct users to authorization endpoint

To start the OAuth process, your client application must redirect the user to the ID.me authorization endpoint. There, the user signs in and chooses whether to grant your application access.

Authorization endpoint

1https://api.id.me/oauth/authorize?client\_id=CLIENT\_ID&redirect\_uri=REDIRECT\_URI&response\_type=code&scope=openid%20SCOPE&state=optional&eid=FOO-bar-123

Parameters

NameDescriptionSupported values
client_idThe client identifier received during app registration. It is automatically generated and located in your application dashboard
scopeSpecifies the policy you are requesting access to. To initiate an OpenID Connect transaction, the scope must include openid along with one of the supported valuesView all values
redirect_uriWhere the user is redirected after authorizing an app. Set by the developer within the application dashboard.
response_typeDetermines the authorization typecode
stateAn optional parameter used to pass server-specific state, such as a CSRF token. This value is returned to your redirect URI unchanged.
opAn optional parameter that triggerssignin, signup
eidAn optional parameter to carry through any external identifiers you would like to receive back in the payload response

Receive authorization code

When a user completes the authorization process on ID.me, they will be redirected to your redirect_uri with the authorization code parameter appended.

Redirect URI with code example

1https://example.com/callback?code=488e864b

Exchange authorization code for token payload

Using the authorization code from the previous step, send a request to ID.me’s Token Endpoint (see below) to retrieve the payload containing your access_token and refresh_token. Each token’s expiration can be found within the payload.

  • Endpoint: https://api.id.me/oauth/token
  • Request method: POST
  • Response type: application/JSON

Parameters

NameDescription
codeThe authorization code you received in the previous step
client_idThe client ID assigned during app registration. It is automatically generated and available in your application dashboard.
client_secretA secret identifier assigned during app registration. It is automatically generated and available in your application dashboard.
redirect_uriWhere the user is redirected after authorizing an app. Set by the developer within the application dashboard.
grant_typeThe only supported value is authorization_code

CURL example

1curl -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
Important

Replace the CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, and SCOPE with your inputs

Obtain ID token

Parameters

NameDescription
access_tokenA credential that is used with every API call to ensure ID.me recognizes that you have authorization to make a request
id_tokenA JSON Web Token (JWT)
token_typeRepresents how an access_token will be generated and presented for resource access calls
expires_inDescribes the lifetime of the access_token in seconds
refresh_tokenContains the information required to obtain a new access_token
refresh_expires_inDescribes the lifetime of the refresh_token in seconds
scopeDefines the policy you are requesting permission to access

Example payload

1{
2 "access_token" : "a0b1c2d3f4g5h6i7j8k9l0m1n2o3p4q5",
3 "token_type" : "bearer",
4 "expires_in" : "300",
5 "refresh_token" : "e7c77fe1fd5ece9aaccb129f6dd39431",
6 "refresh_expires_in" : "604800",
7 "scope" : "military",
8 "id_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO\niJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT\nc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5\nhbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb\nAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb\n3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3\nqCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"
9}

Validate ID token

To ensure the ID token was issued by a trusted source, you need to validate its JWT signature.

ID.me signs the token using the RS256 algorithm. To verify the signature, retrieve the public key from the OpenID Connect server. You can fetch this key from the JWKS endpoint:

1https://api.idmelabs.com/oidc/.well-known/jwks

This endpoint is referenced in the OIDC discovery document and available in the configuration settings of your developer dashboard.

Example JSON Web Token (JWT)

1eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO
2iJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT
3c3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5
4hbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb
5An6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb
63YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3
7qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA
View on JWT.IO

Decode ID token for user payload

The ID token contains details about the user and their authentication status. The following steps explain how to decode the token, which is formatted as a JSON Web Token (JWT), to extract the necessary user information.

Decoded header payload

Key descriptions

NameDescription
typThe Type Header Parameter is used by JWT applications to declare the media type
algThe Algorithm Header Parameter is used by JWT applications to declare the algorithm type
kidThe Key Identifier is an optional header that holds a key identifier that is useful when you have multiple signing keys and need to locate the correct one to verify signatures
issThe Issuer identifies the principal that issued the JWT
subThe Subject is the identifier for the end user (the subject of the token)

Decoded header payload example

1{
2 "typ": "JWT",
3 "alg": "RS256",
4 "kid": "KALesIJUU4nCAc-RSu2dKLdbH-BakutgzA5V7hBoQRo",
5 "iss": "https://api.idmelabs.com/oidc",
6 "sub": "f169c34d007b4510a73ba7998c081ea0"
7}

Decoded ID token payload

Key descriptions

NameDescription
audAudience identifies the recipients that the JWT is intended for and the value should match the client who is receiving the token
expExpiration time indicates when the token will expire (measured in seconds)
iatIssued at indicates when the token will expire (measured in seconds)
uuidA unique identifier associated with the member’s ID.me account

Decoded ID token payload example

1{,
2 "aud": "8749d197447c364b219afbd4b613ebd0",
3 "exp": 1616364069,
4 "iat": 1616346069,
5 "email": "rod.hamill@id.me",
6 "fname": "Rod",
7 "lname": "Hamill",
8 "street": "72146 Okuneva Heights",
9 "city": "Jeffereyburgh",
10 "state": "Hawaii",
11 "zip": "94468-5006",
12 "birthdate": "1959-12-08",
13 "eid": "FOO-bar-123",
14 "uuid": "d733a89e2e634f04ac2fe66c97f71612"
15}

Exchange access token for ID token

This step is optional and only necessary if you would like to use an ID token in place of the access token.

  • Endpoint: https://api.id.me/api/public/v3/userinfo
  • Request method GET
  • Response type application/JSON

Parameters

NameDescription
access_tokenA token included with every API request that allows ID.me to verify your authorization to access protected resources
callbackIf your AJAX application requires a JSONP response, include a callback parameter in the API call to wrap the response

CURL example

1curl -X GET -d "access_token=488e864b" https://api.id.me/api/public/v3/userinfo

Example payload

1"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO
2iJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT
3c3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5
4hbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb
5An6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb
63YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3
7qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"

Parse JSON response

Parsing the JSON response accurately is essential for building a scalable and reliable integration. How your application retrieves and handles this data will determine whether it can adapt to changes, such as the addition of new attributes, without breaking.

Best practice
  • Use the handle field to index attribute values

  • Validate only attributes that are included in the response

  • Store raw JSON responses for auditing and troubleshooting

  • Create a database table to store verification status, uuid, and authoritative data from the ID.me API

  • Use the uuid as a foreign key to link user activity across your application

  • Pre-fill form fields to improve the user experience after verification

  • Do not assume attributes or status values will be returned in a specific order

Example data types

The type of each attribute determines how data will be returned from the ID.me API. You may receive any of the following types.

String

1{
2 "email": "testing@id.me"
3}

Integer

1{
2 "age": 21
3}

Array

1{
2 "covid_vaccine_records": [
3 {
4 "brand": "Pfizer",
5 "date": "2022-01-01T00:00:00-05:00",
6 "type": "primary"
7 },
8 {
9 "brand": "Pfizer",
10 "date": "2022-02-02T00:00:00-05:00",
11 "type": "primary"
12 }
13 ]
14}

Object

1{
2 "previous_addresses": [
3 {
4 "normalized_street": "8281 Greensboro Drive",
5 "street1": "8281 Greensboro Drive",
6 "street2": "",
7 "city": "West McLean",
8 "state": "VA",
9 "province": "",
10 "zip": "22102",
11 "country": "US",
12 "normalized": "false",
13 "primary": "false"
14 },
15 {
16 "normalized_street": "6647 WILDFLOWER DR S",
17 "street1": "6647 WILDFLOWER DR S",
18 "street2": "",
19 "city": "COTTAGE GROVE",
20 "state": "MN",
21 "province": "",
22 "zip": "55016",
23 "country": "US",
24 "normalized": "false",
25 "primary": "false"
26 }
27 ]
28}
Important

Do NOT assume that all attribute values will be strings