OAuth 2.0

ID.me uses OAuth to provide authorized access to its API. We currently use OAuth 2 draft-22 This section describes how you can use the OAuth 2 protocol to to gain access to a user's community data. Requests to retrieve user data require an access_token that is used to query ID.me's REST API. These tokens are unique to a user and should be stored securely. An access_token expire 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 is 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

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=SCOPE&state=optional

Replace CLIENT_ID, REDIRECT_URI, and SCOPE with appropriate inputs

ID.me Widget (Optional)

<span id='idme-wallet-button' data-scopes='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.
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
  • 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 Access Token

    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 Access Token

    Example Payload

    { "access_token" : "a0b1c2d3f4g5h6i7j8k9l0m1n2o3p4q5" "token_type" : "bearer" "expires_in" : "300" "refresh_token" : "e7c77fe1fd5ece9aaccb129f6dd39431" "refresh_expires_in" : "604800" "scope" : "military" }

    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.
    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. Exchange Access Token For User Data

    Protected REST endpoints can be access by making HTTP requests with the access_token for a given user. The ID.me server will validate the access_token to ensure it has not expired and that its scope covers the requested resource.

    Endpoint

    https://api.id.me/api/public/v3/attributes.json

    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

    { "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": "Zip Code", "value": "44058-1478" }, { "handle": "eid", "name": "External Identifier", "value": "FOO-bar-123" } ], "status": [ { "group": "military", "subgroups": [ "Service Member" ], "verified": true } ] }

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

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

    Integer

    { "handle": "age", "name": "Age", "value": 21 }

    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

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

    Do not expect all attribute values to be a string.