Welcome to ID.me for developers! If you are interested in integrating ID.me, you are in the right place. Here we will cover how to get started implementing ID.me.
OpenID Connect Integration
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 and customize the colors of the buttons on the ID.me screen are also available.
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
<div id="idme-verification">
<a href="https://api.id.me/oauth/authorize?client_id=[YOUR_CLIENT_ID]&redirect_uri=[YOUR_REDIRECT_URI]&response_type=code&scope=openid government&state=488e864b&nonce=123456">
<img src="https://s3.amazonaws.com/idme/developer/idme-buttons/assets/img/signin.svg" height="50"/>
</a>
<p>
ID.me is our trusted technology partner in helping to keep your personal information safe. They specialize in digital identity protection and help
us make sure you're you—and not someone pretending to be you—before we give you access to your information.
<a href="https://www.id.me/about">Learn more about ID.me</a>.
</p>
</div>
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 include:openid
|
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
id_token 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 sign in or sign up once redirected to ID.me.
Supported values include:signin
signup
|
nonce
|
An optional parameter value needs to include per-session state and be unguessable to attackers. One method to achieve this for Web Server Clients is to store a cryptographically random value as an HttpOnly session cookie and use a cryptographic hash of the value as the nonce parameter. In that case, once in the returned ID Token is compared to the hash of the session cookie to detect ID Token replay by third parties. A related method applicable to JavaScript Clients is to store the cryptographically random value in HTML5 local storage and use a cryptographic hash of this value. |
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 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
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": "http://idmanagement.gov/ns/assurance/ial/2/aal/2",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiOiJodHRwczovL2FwaS5p\nZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNTc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOj\nE2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5hbWUiOiJWRVJPTklDQSIsImxuYW1lIjoiUEVSU0lOR0VSIiwiemlwIjoiMjIxMDIiLCJ1\ndWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.QwdnbAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWo\nA5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM\n8uo6CD3Ql3qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"
}
Parameters
Name | Description |
---|---|
id_token
|
A JSON Web Token(JWT) |
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 |
Example Encoded ID Token
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiOiJodHRwczovL2FwaS5p
ZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNTc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOj
E2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5hbWUiOiJWRVJPTklDQSIsImxuYW1lIjoiUEVSU0lOR0VSIiwiemlwIjoiMjIxMDIiLCJ1
dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.QwdnbAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWo
A5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM
8uo6CD3Ql3qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA
Step 5: Verify User Token
Now, we need to verify that the ID Token sent was from the correct place by validating the JWT's signature. headers.payload.signature
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.
Ruby Example
require "base64"
encoded_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiOiJodHRwczovL2FwaS5p
ZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNTc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOj
E2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5hbWUiOiJWRVJPTklDQSIsImxuYW1lIjoiUEVSU0lOR0VSIiwiemlwIjoiMjIxMDIiLCJ1
dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.QwdnbAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWo
A5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM
8uo6CD3Ql3qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"
encoded_headers = encoded_token.split[0]
plain_headers = Base64.decode64(encoded_headers)
Decoded Header Payload Example
{
"typ": "JWT",
"alg": "RS256",
"kid": "KALesIJUU4nCAc-RSu2dKLdbH-BakutgzA5V7hBoQRo"
}
Parameters
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. |
Step 6: Decode ID Token For User Payload
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.
Ruby Example
require "base64"
encoded_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IktBTGVzSUpVVTRuQ0FjLVJTdTJkS0xkYkgtQmFrdXRnekE1VjdoQm9RUm8ifQ.eyJpc3MiOiJodHRwczovL2FwaS5p
ZG1lbGFicy5jb20vb2lkYyIsInN1YiI6ImYxNjljMzRkMDA3YjQ1MTBhNzNiYTc5OThjMDgxZWEwIiwiYXVkIjoiZTE3OWUzNTc3NTAzMjBlMmU2NTJjODBiNjFjNGRjMDIiLCJleHAiOj
E2MjU1MTI3ODQsImlhdCI6MTYyNTQ5NDc4NCwiZW1haWwiOiJ0ZXN0aW5nQGlkLm1lIiwiZm5hbWUiOiJWRVJPTklDQSIsImxuYW1lIjoiUEVSU0lOR0VSIiwiemlwIjoiMjIxMDIiLCJ1
dWlkIjoiZjE2OWMzNGQwMDdiNDUxMGE3M2JhNzk5OGMwODFlYTAifQ.QwdnbAn6kbnzSvASa8qEMTJO-T-jzkJAfJdLViX188N2ny1DLBjn1AxgsydXmnzeyCtfv9Mn-rjLFtsEAPXMbWo
A5maU0Lqt03hbSEbvevksr6xzD0j9mzQdWb3YXHkSS-A3dKkl4KM5TiO7BY8W5Xmhp0YivtcW2_C24xdxukYBgR1Y6lmjaKS3SGQRkjO31mj8_qxlAP4RuC9U2cmHx-w2HYVJfwpyauzmM
8uo6CD3Ql3qCP88bcyJtF2O9cEpvW9E47CcaueGLjBF9_Qe0u1IWzcX77rCTnxMounfjmYDn7Md0JAl6-Q6E23yu-Zibg8CFytmDDm4pGbEA7g8BA"
encoded_payload = encoded_token.split[1]
plain_payload = Base64.decode64(encoded_payload)
Payload Example
{
"iss": "https://api.idmelabs.com/oidc",
"sub": "f169c34d007b4510a73ba7998c081ea0",
"aud": "8749d197447c364b219afbd4b613ebd0",
"exp": 1616364069,
"iat": 1616346069,
"email": "walker.cassin@id.me",
"fname": "Walker",
"lname": "Cassin",
"street": "852 Adam Plains",
"city": "North Alphonso",
"state": "Arizona",
"zip": "48940",
"birthdate": "1995-08-08",
"uuid": "d733a89e2e634f04ac2fe66c97f71612"
}
Parameters
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
|
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. |
Step 7: Exchange Access Token For User Payload
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.
CURL Example
curl -X GET -d "access_token=488e864b" https://api.id.me/api/public/v3/attributes.json
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
{
"iss": "https://api.idmelabs.com/oidc",
"sub": "f169c34d007b4510a73ba7998c081ea0",
"aud": "8749d197447c364b219afbd4b613ebd0",
"exp": 1616364069,
"iat": 1616346069,
"email": "osvaldo.white@id.me",
"fname": "Osvaldo",
"lname": "White",
"street": "47355 Ruthann Drive",
"city": "South Bradly",
"state": "Wyoming",
"zip": "06401",
"birthdate": "2004-05-04",
"uuid": "d733a89e2e634f04ac2fe66c97f71612"
}
Requirements
Errors
If the user denies the access request or if the request is invalid, the client will be informed using the following parameters appended to the redirect uri:
Parameters
Name | Description |
---|---|
error
|
A single error code as described below. |
error_description
|
A human-readable text providing additional information, used to assist in the understanding and resolution of the error occurred. |
error_uri
|
A URI identifying a human-readable web page with information about the error, used to provide the end-user with additional information about the error. |
Codes
Code | Description |
---|---|
invalid_request
|
The request is missing a required parameter, includes an unsupported parameter or parameter value, or is otherwise malformed. |
invalid_client
|
The client identifier provided is invalid. |
invalid_redirect_uri
|
The redirection URI provided does not match a pre-registered value. |
access_denied
|
The end-user or authorization server denied the request. |
unsupported_response_type
|
The requested response type is not supported by the authorization server. |
invalid_scope
|
The requested scope is invalid, unknown, or malformed. |