Making the Most of OpenID Tokens
As explained in the basic concepts, there are three types of tokens - Access Tokens, ID Tokens and Refresh Tokens. The same primary function of each type is to act as a credential (a proof of identity) that allows you (and your application) to validate that an identity is authenticated against the HID Authentication Service, as well as accessing protected resources owned by this identity.
However, each type of token is useful in different situations and it is important to understand when and where they are needed and how that can help you to secure your application.
OpenID Tokens are defined through the OAuth and OpenID standards:
As a token allows access to the HID Authentication ServiceAPIs, as well as the end user's data, it must be protected by your application.
It is strongly recommended that the token is:
Strictly personal to the authenticated user and should not be disclosed to any third party
Stored securely (encrypted or hashed at minimum)
Stored only until it expires, and should be wiped from your system afterward
All tokens expire and the HID Authentication Service always passes an expires_in attribute along with any token that is returned to your application. This attribute indicates, in milliseconds, the validity duration of the token.
Sample response from the token endpoint with an access token
{
"access_token": "PIn9gwAAAW+o0WgmEhqlRRuNimeuctqp04cVogNQ",
"refresh_token": "77949230",
"context": {
"LEVEL_OF_ASSURANCE": "urn:hidaaas:policy:at_stdpwd"
},
"token_type": "Bearer",
"expires_in": 3600
}
Access Tokens - Access OpenID and SCIM
Access tokens are the most common tokens and are, by default, returned upon any successful authentication with the HID Authentication Service. They can be compared to a session ID. They are lightweight encrypted pieces of data that identify a Client ID or user's session.
Access tokens are perfect to be used as a credential to access protected OpenID and SCIM endpoints. By getting an access token for a privileged user (Organization Administrator) or Client ID (Client ID M2M), your application can then access resources through OpenID and SCIM, such as Users, Client IDs, and Roles.
To use an access token with a protected OpenID or SCIM endpoint, simply pass it in the Authorization header of a request, with the prefix Bearer.
Sample request where the access token is used to search for a Client ID
POST https://[base-server-url]/scim/{tenant}/v2/Users/.search HTTP/1.1
Authorization: Bearer PIn9gwAAAW+lGUwYedd6o22q9vQ3hvUTiJW0qJtL
Content-Type: application/json;charset=UTF-8
{
"schemas":[
"urn:ietf:params:scim:api:messages:2.0:SearchRequest" ],
"filter":"externalId eq \"655817402088574941876708488070484658763453311419\"",
"sortBy":"id",
"sortOrder":"descending",
"startIndex":0,
"count":100
}
For further examples of the tokens, see Retrieve the Authentication Result and Access Token.
ID Tokens - Carry and Validate User/Client ID Information
An ID Token is a signed JWT (JSON Web Token) containing readable information about the user / Client ID. The attributes of that token are called claims.
For further information about the JWT standard, go to https://tools.ietf.org/html/rfc7519.
It enables data to be exchanged about the user, as well as validating that the user was authenticated against the HID Authentication Service (by verifying the signature of the token).
To obtain an ID Token, simply use the openid profile scope in your authentication request:
POST https://[base-server-url]/{tenant}/authn/token HTTP/1.1
Authorization: Bearer YOUR_BEARER_TOKEN_FOR_CLIENTID
Content-Type: application/json;charset=UTF-8
grant_type=password&username=YOUR_USER_EXTERNALID&password=YOUR_USER_PASSWORD&scope=openid profile
The response contains a new id_token attribute:
{
"access_token": "PIn9gwAAAW+pyLal6TvxVPeTovUl7vhzlcNnjw+l",
"id_token": "eyJraWQiOiIxNTc4MDY0MDc3MDA4IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiMUJsTUN4TXNYVUpsNHd0RmZjbTV6QSIsInN1YiI6InRlc3RAbWFpbC5mciIsImF1ZCI6IjIxNzgxNDE1NTQ0NjE2ODY0NzE1NDA0ODUwNTg3NDE0NDMzNjIyOTQ4MTg0MTgyMiIsImFjciI6InVybjpoaWRhYWFzOnBvbGljeTphdF9zdGRwd2QiLCJhdXRoX3RpbWUiOjE1NzkxMDE1MDEsImlzcyI6Imh0dHBzOlwvXC90ZXN0LmFhYXMuaGlkY2xvdWQuY29tXC9pZHBcL3RhNjk3ZGFiZjEyNzgwNjQwNDk5NTBcL2F1dGhuIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdEBtYWlsLmZyIiwiZXhwIjoxNTc5MTA1MTAxLCJpYXQiOjE1NzkxMDE1MDF9.KjyepaW3HUmIq2ihO7jJMjdDqVMx26Kj8B3FR8plzLtV_9TM3DAPe2Lzq8kfK-JxHSWC1DxTxwwtnwkMD8J098JWvSXtiwZ8uwyAbjCCTpzrmCxHjHNev_K9J_7_xcMFib94PsfOihCocajBy3vZ-QwYpxU30du4VUUNQqU7Uzy9Rrrx6Zw5H7_X0TSEJHk_jwN1nfw5Dhl0bqcb4UwCoFUpryT9B818rL8D69ncwFNNoglLvbO9YXPn7oKdyzua_PLjjRWa8AS5bj6btVOkXBZdH2noaYGJinxCPE5xGngw1dsrtzO6qGG1js8WccS67mEFWSiCBFCAlSjefHkEjg",
"context": {
"LEVEL_OF_ASSURANCE": "urn:hidaaas:policy:at_stdpwd"
},
"token_type": "Bearer",
"expires_in": 3600
}
The token is a base64 URL encoded data structure. It contains a header, a body and a signature separated by dots:
eyJraWQiOiIxNTc4MDY0MDc3MDA4IiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJhdF9oYXNoIjoiMUJsTUN4T XNYVUpsNHd0RmZjbTV6QSIsInN1YiI6InRlc3RAbWFpbC5mciIsImF1ZCI6IjIxNzgxNDE1NTQ0NjE2ODY0NzE1NDA0ODUwNTg3NDE0ND MzNjIyOTQ4MTg0MTgyMiIsImFjciI6InVybjpoaWRhYWFzOnBvbGljeTphdF9zdGRwd2QiLCJhdXRoX3RpbWUiOjE1NzkxMDE1MDEsIml zcyI6Imh0dHBzOlwvXC90ZXN0LmFhYXMuaGlkY2xvdWQuY29tXC9pZHBcL3RhNjk3ZGFiZjEyNzgwNjQwNDk5NTBcL2F1dGhuIiwicHJl ZmVycmVkX3VzZXJuYW1lIjoidGVzdEBtYWlsLmZyIiwiZXhwIjoxNTc5MTA1MTAxLCJpYXQiOjE1NzkxMDE1MDF9.KjyepaW3HUmIq2ih O7jJMjdDqVMx26Kj8B3FR8plzLtV_9TM3DAPe2Lzq8kfK-JxHSWC1DxTxwwtnwkMD8J098JWvSXtiwZ8uwyAbjCCTpzrmCxHjHNev_K9J _7_xcMFib94PsfOihCocajBy3vZ-QwYpxU30du4VUUNQqU7Uzy9Rrrx6Zw5H7_X0TSEJHk_jwN1nfw5Dhl0bqcb4UwCoFUpryT9B818rL 8D69ncwFNNoglLvbO9YXPn7oKdyzua_PLjjRWa8AS5bj6btVOkXBZdH2noaYGJinxCPE5xGngw1dsrtzO6qGG1js8WccS67mEFWSiCBFCAlSjefHkEjg
To extract the data, simply decode the header and the body with base64URL.
The header contains the signature algorithm (always RSA with SHA256) as well as the key ID used to sign the token. For further information about using this key ID, see Verify the signature of an ID Token.
{
"kid": "1578064077008",
"typ": "JWT",
"alg": "RS256"
}
The body contains the claims about the user and the Client ID used for the authentication, in particular the:
-
subject (sub), the end user that is actually authenticated.
-
audience (aud), the client ID that authenticated the end user.
-
authentication context class (acr), the authentication policy used for the authentication.
-
authentication time (auth_time).
-
issuer (iss), the platform of the HID Authentication Service that issued the token.
-
expiry (exp), time at which the token will expire.
-
issued at (iat), time at which the token was issued.
{
"at_hash": "1BlMCxMsXUJl4wtFfcm5zA",
"sub": "test@mail.com",
"aud": "217814155446168647154048505874144336229481841822",
"acr": "urn:hidaaas:policy:at_stdpwd",
"auth_time": 1579101501,
"iss": "https://[base-server-url]/{tenant}/authn",
"preferred_username": "test@mail.com",
"exp": 1579105101,
"iat": 1579101501
}
For further examples of the tokens, see Retrieve the Authentication Result and Access Token.
Verify the Signature of an ID Token
Another important feature of ID Tokens is the signature, the third part of the token structure:
KjyepaW3HUmIq2ih
O7jJMjdDqVMx26Kj8B3FR8plzLtV_9TM3DAPe2Lzq8kfK-JxHSWC1DxTxwwtnwkMD8J098JWvSXtiwZ8uwyAbjCCTpzrmCxHjHNev_K9J
_7_xcMFib94PsfOihCocajBy3vZ-QwYpxU30du4VUUNQqU7Uzy9Rrrx6Zw5H7_X0TSEJHk_jwN1nfw5Dhl0bqcb4UwCoFUpryT9B818rL
8D69ncwFNNoglLvbO9YXPn7oKdyzua_PLjjRWa8AS5bj6btVOkXBZdH2noaYGJinxCPE5xGngw1dsrtzO6qGG1js8WccS67mEFWSiCBFCAlSjefHkEjg
The signature can be used to verify that the token was issued by the HID Authentication Service and was not tampered with by a third party.
The signature is computed by the HID Authentication Service
base64URLEncode(
signWithRSA(
hashWithSHA256(
base64URLEncode( headerJSON ) + "." + base64URLEncode( body )
)
, PRIVATE_KEY_OF_HID_AUTHENTICATION_SERVICE )
)
To verify the signature:
base64URLEncode(
verifyRSASignature(
token,
PUBLIC_KEY_OF_HID_AUTHENTICATION_SERVICE )
)
The verification operation consists of re-computing the signature from the base64URL-encoded header and body, then hashing the result with SHA256 and finally encrypting it with the RSA public key. You compare this result to the signature provided in the token to verify that the token is authentic.
To obtain the public key of the HID Authentication Service, you need to fetch the JSON Web Key Set (JWKS) corresponding to your tenant.
Sample request to the JWKS endpoint:
GET https://[base-server-url]/{tenant}/authn/jwks HTTP/1.1
Content-Type: application/json;charset=UTF-8
The response contains a list of keys in the JWK (JSON Web Key) format. This format is defined in the following standard: https://tools.ietf.org/html/rfc7517.
Each key contains the:
-
Key ID (kid), this is the ID of the key
-
e and n (exponent and modulus)
-
PEM representation of the key (x5c)
-
usage (use), indicating if the key is used to encrypt or sign
You can use the Key ID (kid) to find the key that matches the key used to sign the token. In the following example, the first key (1578064077008) matches the header kid of the tokens above.
{
"keys": [
{
"kty": "RSA",
"x5t#S256": "pG-QgV1Zz(...)",
"e": "AQAB",
"use": "sig",
"kid": "1578064077008",
"x5c": [
"MIIDljCCAn6gAwIBAgIGAW9r8uDQ=(...)"
],
"alg": "RS256",
"n": "h0nEt0FfgOPsKf4wHfv-3Ng7Pcm(...)"
},
{
"kty": "RSA",
"x5t#S256": "iIbKoEGkd2(...)",
"e": "AQAB",
"use": "enc",
"kid": "1578064077550",
"x5c": [
"MIIDlzCCAn+gAwIBAgIGAW9r8uLu=(...)"
],
"alg": "RS256",
"n": "l8DLpS988oRoMqhcDOHodvZa5KpfN(...)"
}
]
}
Refresh Tokens - Extend User Sessions without Prompting
Refresh tokens are used to obtain a new access token when a token has expired. This can be very useful as it allows your application to refresh the session of your end user without prompting for credentials again.
When your application detects that an access token has expired (either by checking the expires_in attribute, or from receiving a error code from an HID Authentication Service endpoint), a refresh token can be used to obtain a new access token.
Leveraging refresh tokens requires that your Client ID was registered with the following configuration:
-
hid_client_scopes must contain the scope offline_access
-
hid_client_consentprompt must be set to false (only applies for the Password grant flow)
For further information about Client ID registration, see Managing Users, Groups and Roles.
- Authorization Code Flow
- Password Grant Flow
It is not possible to get refresh tokens with the Client Credential flow. For further information about OpenID flows, see OpenID Authentication Flows.
Once your client ID is configured as indicated above, you will receive a refresh token by passing offline_access in the parameter scope of an authentication request to the token endpoint.
When your application detects that an access token has expired, another call to the token endpoint with that refresh token will allow you to get another access token.
In order to request a refresh token for the password grant flow, an access token obtained for the Client ID is passed in the authorization header (see Client ID authentication with a password or Client ID authentication with JWT (PKI)).
POST https://[base-server-url]/{tenant}/authn/token HTTP/1.1
Authorization: Bearer YOUR_BEARER_TOKEN_FOR_CLIENTID
Content-Type: application/json;charset=UTF-8
grant_type=password&username=YOUR_USER_EXTERNALID&password=YOUR_USER_PASSWORD&scope=offline_access
An access token for the end user is available in the response:
{
"access_token": "PIn9gwAAAW+o0WgmEhqlRRuNimeuctqp04cVogNQ",
"refresh_token": "77949230",
"context": {
"LEVEL_OF_ASSURANCE": "urn:hidaaas:policy:at_stdpwd"
},
"token_type": "Bearer",
"expires_in": 3600
}
With the obtained an access token, upon expiry, you can request for another access token due to the refresh token retrieved in the previous request.
An access token for the Client ID is passed in the Authorization header:
POST https://[base-server-url]/{tenant}/authn/token HTTP/1.1
Authorization: Bearer YOUR_BEARER_TOKEN_FOR_CLIENTID
grant_type=refresh_token&refresh_token=77949230&scope=offline_access&client_id=YOUR_CLIENTID
Do not confuse the access tokens that are manipulated here - two access tokens are obtained, one for the Client ID, one for the end user.
The access token obtained for the Client ID (YOUR_BEARER_TOKEN_FOR_CLIENTID) is obtained through a client credential flow and serves the purpose of authenticating your application. This is not the token to be refreshed.
The token obtained for the end user through a password grant (PIn9gwAAAW+o0WgmEhqlRRuNimeuctqp04cVogNQ) is the one to refresh.