Next Identity Token Service

Next Identity Token Service introduces a stand-alone authorization service for integrating applications to consume scoped access. The Token Service uses the OAuth2 framework to delegate tokens to relying parties (RPs), third-parties, and downstream applications (m2m) that have the authorization scope set based on that application’s permissions. An application that uses the Next Identity platform will be configured based on their integration type and the token handed back to them will be scoped based on that set of scopes that they can then use against specific APIs.

Enhancements to IDP Endpoints

The Next Identity Token Service has the following enhancements to the IDP endpoints:

:white-check-mark: Token

  • Client credential grant to obtain access token
  • Token scopes to limit apps authorization
  • Support for both opaque and JWT access token
  • Access token lifetime is configurable per client. Default token lifetime is 60 minutes.

:white-check-mark: Token introspection

Token types

NI Token Delegation can be configured to either hand back an opaque token or a JWT. The opaque access token is a randomly generated string that allows the RP to use the /introspect endpoint to check the validity as well as the /logout endpoint to revoke the session. Another option is to configure a JWT access token which allows an RP to check the validity without a call to external service which can reduce complexity and save on performance.

An opaque access token is a random sequence of alphanumeric characters that contains no inherent meaning. The validity and scope is checked against the authorization service. An opaque token can also be revoked in order to invalidate.

Example:

"access_token": "151tR-O1wyuvH7jQ55bPHth96-VyqUIVcjQdrD-86o"

JWTs, in contrast, are not opaque. JWT contains metadata that can be extracted and interpreted by any bearer that has the token. JWT usually contains real information so it can be of variable size depending on the claims contained within it and the algorithm used to sign it.

Any holder of the JWT can inspect it, validate it and then optionally make authorization decisions based on the claims presented in it. Validating the JWT means usually involves following:

  • verifying JWT structure
  • decoding the base64 encoding
  • verifying the key is correct
  • verifying the signature
  • verifying the required claims are present in the token
  • verifying the expiry of the JWT

Example:

"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImM2YWY3ZDhmYzJmMjQ4OGE5MTY1NDJjMzI1N2ZkOWQ1Iiwiamt1IjoiaHR0cHM6Ly9pZC51YXQuZXUubmV4dHJlYXNvbi5jb20vLndlbGwta25vd24vandrcyJ9.eyJpc3MiOiJodHRwczovL2lkLnVhdC5ldS5uZXh0cmVhc29uLmNvbSIsInN1YiI6ImRmOWE5NGM4LWIzZDItNDdiYS04YTNkLTVlZDgzYmM5MDI4MCIsImNsaWVudF9pZCI6ImN3bXdnOWc4eGF5NzJydXM4N2E2OGh4dDg2eDQ5dDN3IiwiYXVkIjpbImN3bXdnOWc4eGF5NzJydXM4N2E2OGh4dDg2eDQ5dDN3Il0sImlhdCI6MTY1NDYzODMzOSwibmJmIjoxNjU0NjM4MzM5LCJleHAiOjE2NTQ2MzgzNjksImp0aSI6Ii1QTW5jckRYWGQ3bjhnNkthOFJNRkVpeS1FTFhmcG5yS2dGUllQRmhXNEkiLCJzY29wZSI6InByb2ZpbGUgb3BlbmlkIHBob25lIGVtYWlsIGFrYW1haTptYXJrZXQgbmk6c29jaWFsX3Byb2ZpbGUgYWRkcmVzcyJ9.KKRURcDnSh53IqrJvPgG-ET6KNJ4v6gdtWndBHEJ0iUtbm3Op29wvTWseT6movX7DsMj155HjxMqagHeerYlmo9T6RMKdRev5--pEUIYx4GGP7DMkFn3XdToxTPCvXaFtW4afy7jJVBi-B7oPPFihC9Zy5quwKEsa6I41khhuZ-pehvW6fUbcac9E0f3Cv8Sz2YalhS1TKH1iAc1IkYLyVdzUUVvmpOhGj_wm-pb9TEZ2MLe6mqWmZ2Sqhrw5c_X9tqs8zmnsM2Fqy_onh7hMmg2rxIjQsFiaA6xK8o_w3cynzLIr33KCdZKUGULzOVQMFDJuevinJkI9MYSh7krIw"

When to Use JWT

  • Federation is desired. An app can authenticate using Next Identity and then present that token to a third-party IDP or application to be verified.
  • Improve performance that comes as a result of token self-validation.

When to use Opaque token

  • There is no federation required in the API flow. The IDP that issue the token is the same which validates the token.
  • There is no requirement to allow the token bearer to inspect the claims within the token or use it for applying flexible policies.
  • There are specific scenarios when you explicitly need to revoke access token before it expires. JWT automatically expires based on token expiry set at the time of creation.

Scopes

Token Scopes are a mechanism to limit an application's access to a user's account. An application can request one or more scopes and the access token issued to the application will be limited to the scopes granted.

Standard scopes are pre-defined within the OAuth2.0 and OpenId Connect specification along with claims associated with them.

Custom scopes can be configured and attached to the access token on the response. If the scopes are associated with a known system (example below), claims can also be configured within those scopes.

What are scopes and claims?

OpenID Connect (OIDC) scopes are used by an application during authentication to authorize access to a user's details, like name and email. Each scope returns a set of user attributes, which are called claims. The scopes an application requests depend on which user attributes the application needs.

Token Scopes are a mechanism to limit an application's access to a user's account. An application can request one or more scopes and the access token issued to the application will be limited to the scopes granted.

Standard scopes

ScopeClaims
emailemail, email_verified
addressstreet address, localitycountryregionpostal_code
profilegiven_namemiddle_namefamily_namebirthdategenderupdated_at
phonephone_numberphone_number_verified
openidsubauth_timeacr

Custom scopes

Custom Scopes give the application a way to attach additional authorizations to the token. They can be defined within the client configuration and will be handed back in the token response based on what was requested. It is recommended to add custom scopes with a prefix, a scope name that makes sense, and a suffix ex: prefix:scope_name:suffix

Prefix

The prefix should denote the data source. For example, if Akamai is the source of the data being requested, you would append akamai to the scope name. If the source of data is an external service such as AWS Cognito, you would append cognito to the scope.

Scope Name

The scope name should be as human readable as possible since its purpose is to be interpreted by downstream applications. If there is a certain group of data within Akamai then is being requested, the scope name might be something like social_profile.

Suffix

The suffix indicates the permissions that the application has by obtaining that token. Examples include read, write, delete, or * (all).

Example custom scope

akamai:social_profile:read

Custom claims

If the data source is supported by Next Identity, custom claims can also be associated with the scope. For example, Next Identity supports Akamai Identity Cloud as a data source and therefore scopes associated with Akamai (prefix) can have claims that are outside of the standard returned in the JWT. Here is an example of Azure Active Directory as a data source. The database contains an attribute called companyName, which is associated with a user. So we would define a scope called: ad:user_custom:read . The client application can now request that scope in the login or client credential call. Once the id_token is received and decoded, you would see that claim returned. In the below example, the client application requested the following claims:

openid email profile ad:user_custom (note that the suffix is optional in the request)

{
  "name": "John Smith",
  "nickname": "john.smith",
  "updated_at": "2017-03-30T15:13:40.474Z",
  "email": "[email protected]",
  "email_verified": false,
  "iss": "https://localhost.com",
  "sub": "USER-ID",
  "aud": "YOUR_CLIENT_ID",
  "exp": 1490922820,
  "iat": 1490886820,
  "company_name": "Bizcorp"
}

Authentication example

Next, we are going to explore an example from beginning to end. In this example, we want to log the user in, then obtain some user data as well as permissions to access a restricted resource. We will use the authorization code flow for the authentication then exchange the authorization code for the access token to see the requested scopes. Lastly, we will inspect the ID token to get the user’s details.

In this example, we want to authenticate a user and get the user's name and email information.

  1. Initiate the authentication flow by sending the user to the authorization URL:
https://URL.com/authorize?
  response_type=code&
  client_id=CLIENT_ID&
  redirect_uri=https://YOUR_APP/cb&
  scope=openid%20profile%20email&
  state=STATE_VALUE

📘

Additional information on the scope parameter

The scope parameter includes three OIDC scope values:

  • openid: to obtain the id_token
  • profile: for given_name, family_name, and updated_at
  • email: to get email and email_verified
  1. The user authenticates and is redirected back to your app with the authorization code in the URL.
  2. Grab the authorization code and call the /token endpoint to exchange the auth code for the access token:
POST 'https://URL.com/idp/v1/account/token'
{
    "client_id": "CLIENT_ID",
    "redirect_uri": "https://YOUR_APP/cb",
    "grant_type": "authorization_code",
    "code": "AUTHORIZATION_CODE_HERE",
    "auth_type": "email",
    "user_id": "EMAIL",
    "legal_acceptances": true
}

Response
{
    "token_type": "Bearer",
    "access_token": "NPObrbntB3f7fDFlqSvqlnJi_w-VXbyguc2htf-Qh5s",
    "expires_in": 3600,
    "scope": "openid email profile",
    "refresh_token": "l5ZQ2hroJYosLpcBxc4_JDaoWPc8VFTujEhmMM3XXRg",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJmYW1pbHlfbmFtZSI6ICJEb2UiLAogICJnaXZlbl9uYW1lIjogIkphbmUiLAogICJ1cGRhdGVkX2F0IjogIjIwMTctMDMtMzBUMTU6MTM6NDAuNDc0WiIsCiAgImVtYWlsIjogImphbmUuZG9lQGVtYWlsLmNvbSIsCiAgImVtYWlsX3ZlcmlmaWVkIjogZmFsc2UsCiAgImlzcyI6ICJodHRwczovL0lEUF9ET01BSU4vIiwKICAic3ViIjogIlVVSUQiLAogICJhdWQiOiAiQ0xJRU5UX0lEIiwKICAiZXhwIjogMTI5MDkzMjgyMCwKICAiaWF0IjogMTI5MDgzODY4MjAKfQ==.jcN-CgREp2rd6ImXoY3P7Z9_b4OEQvnQcMgZEUqVmq_J_7cjkFZsdgoygix8vzciUIxVkh1hX33Wi6KUY3bPHsB4VEJ_Xjsqb0D2uLr0zq3Oov7Behq1ckgFt0pFMIOwdBA5nSOK_JUPe8snKvBWQkxI1sSXYxP2EbI9hHON4wxFrYDRwToANVdl6KTQKQH2j-Za7wkTLCeWjvRCV7Hlr2tjeBbskVAYEpnWxhnEpe9VcVJosl4JgP5zrS_yc3n2gIPaQsMp22MnrNtlaIHoPa4rt-aPCWiUdSOg62SeJz9k8E_eA5fpMQselihUQz1fgUX84ywy-FnWhN8D-m5hYw"
}
  1. Extract the ID token from the response, decode it and it will show the following claims:
{
  "family_name": "Doe",
  "given_name": "Jane",
  "updated_at": "2017-03-30T15:13:40.474Z",
  "email": "[email protected]",
  "email_verified": false,
  "iss": "https://IDP_DOMAIN/",
  "sub": "UUID",
  "aud": "CLIENT_ID",
  "exp": 1290932820,
  "iat": 12908386820
}

FAQ

▶️Why do I not receive a refresh token when I use the client_credentials grant?

See answer

The client_credentials grant_type creates non-refreshable tokens per https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.3.

▶️Can I configure my own arbitrary scopes?

See answer

Yes. We recommend you follow the scope guide in this document for naming conventions and for purpose.

▶️Will scopes limit my ability to use my client ID?

See answer

Not yet. Currently scopes and claims are informational and are used to obtain user data and/or to send a signal to an application of authorization. However, the scope of a token doesn’t yet limit the functionality of that token against the IDP endpoints.