OpenID Connect

ID.me uses OpenID Connect (OIDC) to provide authorized access to its API. We currently use OAuth 2 draft-22. OpenID Connect is an open authentication protocol that works on top of the OAuth 2 framework. This section describes how you can use OpenID Connect to gain access to a user's data. Requests to retrieve user data require an access_token along with an id_token which are used to query ID.me's REST API. These tokens are unique to a user and should be stored securely. An access_token expires 5 minutes after being issued.

ID.me supports both a full page redirect to the authorization endpoint as well as a popup window. Once you have registered an application, sample code and documentation will be available on the application details page. The ability to upload your company logo and customize the colors of the buttons on the ID.me screen are also available.

Prerequisites

Create an ID.me Developer Account & Organization

To get started, you will need to create an ID.me developer account and organization to generate your client_id and client_secret. Once created, you can configure custom redirect_uri values to facilitate where ID.me returns the authorization_code

Evaluate Well-Known Endpoints

Leverage the well-known endpoint to obtain critical configuration information. These endpoints provide metadata in a standardized format (JSON) and includes details such as: - The issuer URL - Supported authentication methods - Token endpoin - Public key for verifying tokens - Other essential configuration settings

You can use this information to configure your applications for secure authentication and authorization, ensuring compatibility and compliance with the OIDC standard.

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

Step 1. Direct Users To Authorization Endpoint

The client app must send the user to the authorization endpoint in order to initiate the OAuth process. At the authorization endpoint, the user authenticates on the ID.me server and then grants or denies access to the app.

Authorization Endpoint:

https://api.id.me/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&scope=openid SCOPE&state=optional

Replace CLIENT_ID, REDIRECT_URI, and SCOPE with appropriate inputs

ID.me Widget (Optional)

<span id='idme-wallet-button' data-scopes='openid 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>

Replace CLIENT_ID, REDIRECT_URI, and SCOPE with appropriate inputs

Parameters

Name Description
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. Must include openid in the scope, along with one of the supported values below, to initiate OpenID Connect transactions.
Supported values can be found here:
Standard OAuth/OIDC Scope & SAML AuthnContext Values
redirect_uri Where the user gets redirected after an authorizing an app. Set by the developer within the application dashboard.
response_type Determines the authorization type.
Supported values include:
  • code
  • token
  • id_token
  • code id_token
  • code token
  • code token
  • code id_token token
  • 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 parameter that triggers.
    Supported values include:
  • signin
  • signup
  • eid An optional parameter to carry through any external identifiers you would like to receive back in the payload response.

    Step 2. Receive The Authorization Code

    When the user completes the authorization process on ID.me, we will redirect the user to your redirect_uri with the authorization code parameter appended.

    Redirect URI with code example

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

    Step 3. 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 in the payload.

    CURL 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

    Replace CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, and SCOPE with appropriate inputs

    Endpoint

    https://api.id.me/oauth/token

    HTTP Request Method

    POST

    Response Content 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 gets redirected after an authorizing an app. Set by the developer within the application dashboard.
    grant_type The only supported value is currently authorization_code

    Step 4. Obtain ID Token

    Example Payload

    { "access_token" : "a0b1c2d3f4g5h6i7j8k9l0m1n2o3p4q5" "token_type" : "bearer" "expires_in" : "300" "refresh_token" : "e7c77fe1fd5ece9aaccb129f6dd39431" "refresh_expires_in" : "604800" "scope" : "military" "id_token" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO\niJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT\nc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5\nhbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb\nAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb\n3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3\nqCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA" }

    Parameters

    Name Description
    access_token A credential that is used with every API call, so ID.me recognizes that you have authorization to make that request.
    id_token A JSON Web Token(JWT)
    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 Refresh tokens contain 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

    Step 5. Validate The ID Token

    Now, we need to validate that the ID Token sent was from the correct place by validating the JWT's signature.

    Example JSON Web Token (JWT)

    View on JWT.io

    eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO iJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT c3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5 hbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb An6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb 3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3 qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA

    This token is cryptographically signed with the RS256 algorithim. We'll use the public key of the OpenID Connect server to validate it. In order to do that, we'll fetch the public key from https://api.idmelabs.com/oidc/.well-known/jwks, which is found in the discovery document or configuration menu options.

    Step 5. Decode ID Token For User Payload

    The ID token contains information about a user and their authentication status. The following steps will describe how to decode the ID token, available in JSON Web Token (JWT) format , to get the required information about the user:

    Decoded Header Payload Example

    { "typ": "JWT", "alg": "RS256", "kid": "KALesIJUU4nCAc-RSu2dKLdbH-BakutgzA5V7hBoQRo" }

    Key Description

    Name Description
    typ The Type Header Parameter is used by JWT applications to declare the media type of this complete JWT.
    alg The Algorithm Header Parameter is used by JWT applications to declare the algorithm type of this complete JWT.
    kid An optional header claim which holds a key identifier, particularly useful when you have multiple keys to sign the tokens and you need to look up the right one to verify the signature.

    Decoded ID Token Payload Example

    { "iss": "https://api.idmelabs.com/oidc", "sub": "f169c34d007b4510a73ba7998c081ea0", "aud": "8749d197447c364b219afbd4b613ebd0", "exp": 1616364069, "iat": 1616346069, "email": "[email protected]", "fname": "Rod", "lname": "Hamill", "street": "72146 Okuneva Heights", "city": "Jeffereyburgh", "state": "Hawaii", "zip": "94468-5006", "birthdate": "1959-12-08", "eid": "FOO-bar-123", "uuid": "d733a89e2e634f04ac2fe66c97f71612" }

    Key Description

    Name Description
    iss The Type Header Parameter is used by JWT applications to declare the media type of this complete JWT.
    sub The Algorithm Header Parameter is used by JWT applications to declare the algorithm type of this complete JWT.
    aud An optional header claim which holds a key identifier, particularly useful when you have multiple keys to sign the tokens and you need to look up the right one to verify the signature.
    exp An optional header claim which holds a key identifier, particularly useful when you have multiple keys to sign the tokens and you need to look up the right one to verify the signature.
    iat An optional header claim which holds a key identifier, particularly useful when you have multiple keys to sign the tokens and you need to look up the right one to verify the signature.
    uuid Unique identifer assoicated with the member's ID.me account

    Step 6. Exchange Access Token For ID Token (Optional)

    CURL Example

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

    Endpoint

    https://api.id.me/api/public/v3/userinfo

    HTTP Request Method

    GET

    Response Content Type

    application/json

    Parameters

    Name Description
    access_token A credential that is used with every API call, so ID.me recognizes that you have authorization to make that request.
    callback If you're writing an AJAX application, require a JSONP response, and would like to wrap our response with a callback, all you have to do is specify a callback parameter with the API call.

    Example Payload

    "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiO iJodHRwczovL2FwaS5pZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNT c3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOjE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5 hbWUiOiJURVNUIiwibG5hbWUiOiJVU0VSIiwiemlwIjoiMjIxMDIiLCJ1dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.Qwdnb An6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWoA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb 3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM8uo6CD3Ql3 qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"

    Refer to Step #5 to learn how to parse and decode the values from the JWT

    Step 7. Parse the JSON Response

    Parsing the JSON response correctly is key to implementing a scalable solution. How partners retrieve data from the JSON response can determine if all responses can be handled properly and a change to the payload for any reason such as adding a new attribute won’t break the integration. It is best practice to:

    • Index values using the handle within the object
    • Implement validation only for existing attribute values
    • Store the raw JSON responses for auditing purposes
    • Create table to store the verification status, uuid and authoritative data returned from ID.me REST API
    • Leverage the uuid value as a foreign key on transactions to track ID.me user activity across your application ecosystem
    • Pre-fill form fields to expedite the post verification user experience

    Do not expect all attributes and status values to be returned in the same order within an object or array.

    Example Data Types

    The attribute type determines what data type will be returned from ID.me’s REST API. The following data types should be expected from ID.me’s REST API:

    String

    { "email": "[email protected]" }

    Integer

    { "age": 21 }

    Array

    { "covid_vaccine_records": [ { "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

    { "previous_addresses": [ { "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" } ] }

    Do not expect all attribute values to be a string.