IBM Cloud Identity and Access Management — Tokens in Details

Martin Smolny
Nov 8 · 14 min read

Story Collection “IBM Cloud Identity and Access Management”

This story is part of a collection of stories that explain IBM Cloud Identity and Access Management. The following overview shows the stories that I have already published on medium:

  • Story 1: Overview
    - What is Identity and Access Management?
    - Scenarios covered by Identity and Access Management
    - Tokens used in IBM Cloud
  • Story 2: Token in Details (this story)
    - Response from the token endpoint
    - Access, Refresh and ID Token
    - UAA Token
    - IMS Token
    - Identity Cookie
    - Delegated Refresh Token

Response from the token endpoint

To retrieve any kind of token, you have to call the token endpoint https://iam.cloud.ibm.com/identity/token. I will describe the various ways to invoke that endpoint correctly in the next stories. In this story, I will concentrate on the response structure and its meaning.

{
"access_token": <access_token>,
"refresh_token": <refresh_token>,
"id_token": <id_token>,
"token_type": "bearer",
"expires_in": <expires_in>,
"expiration": <expiration>,
"scope": <scope>,
"uaa_token": <uaa_token>,
"uaa_refresh_token": <uaa_refresh_token>,
"ims_token": <ims_token>,
"ims_user_id": <ims_user_id>,
"identity_cookie": <identity_cookie>,
"identity_cookie_expiration": <identity_cookie_expiration>,
"delegated_refresh_token": <delegated_refresh_token>,
"iam_cookie": <iam_cookie>
}

The response above is already subdivided into several properties that belong together. You can control which of the sections above are returned with the parameter response_type :

  • default value for response_type if not specified at all is cloud_iam
  • specify a space-delimited list of response types if you want other blocks in your response message
  • dependent on the response type selected, additional parameters might be required

The following sections will explain the response types, different sections in the response and required additional parameters if required.

Access, Refresh and ID Token

Related response type: cloud_iam (default)

Required Additional Parameters: none

Comments: The ID Token will only be added to the response if the client id that was used to create the token is configured to create Open ID Connect compliant responses. This is not the default configuration for clients, and only recommended for special situations like integration with frameworks and applications that do not support the OAuth2 model.

Access Token

An IBM Cloud access token — sometimes also called “IAM token” or “Cloud IAM token” — consists of 3 parts:

<header>.<payload>.<signature>

Each of the three parts is encoded with base64url encoding (see also RFC 4648, section 5). Trailing = characters are omitted. This is a sample of an access token:

eyJraWQiOiIyMDE5MDUxMyIsImFsZyI6IlJTMjU2In0.eyJpYW1faWQiOiJJQk1pZC0yNzAwKioqKjRYIiwicmVhbG1pZCI6IklCTWlkIiwiaWRlbnRpZmllciI6IjI3MDAqKioqNFgiLCJnaXZlbl9uYW1lIjoiTWFydGluIiwiZmFtaWx5X25hbWUiOiJTbW9sbnkiLCJuYW1lIjoiTWFydGluIFNtb2xueSIsImVtYWlsIjoiTWFydGluLlNtb2xueUBkZS5pYm0uY29tIiwic3ViIjoiTWFydGluLlNtb2xueUBkZS5pYm0uY29tIiwiYWNjb3VudCI6eyJ2YWxpZCI6dHJ1ZSwiYnNzIjoiOWJmKioqKjRkYTQqKioqZWIxMioqKio0YzZiKioqKjQiLCJpbXMiOjEyMzQ1NiwiaW1zX3VzZXJfaWQiOjk4NzY1NDMyfSwiaWF0IjoxNTY4NDk0NTUxLCJleHAiOjE1Njg0OTgxNTEsImlzcyI6Imh0dHBzOi8vaWFtLmNsb3VkLmlibS5jb20vaWRlbnRpdHkiLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJzY29wZSI6ImlibSBvcGVuaWQiLCJjbGllbnRfaWQiOiJieCIsImFjciI6MSwiYW1yIjpbInB3ZCJdfQ.KIxdpGvsgSvdzdc2lKfN12R6Eox3Tufdac-UGneD2naeIDy-P-GIQPUbMfQdUy3Lw4ZUwP0em
ppnCtYHqW_5zO59MWlbpwvlWTGGEDhDsEhnsraXW91mghFAQjupy0wldczNuoZlyakj0
rh-xoO6LSmAOhSQxz64rdhAuub54poaCUSD-0Juzz0l8_wYcG3pG7jcwiSt1Gh62kSdn
Nku7a9mynDO9dV2HPsr7BtYDk0DnqjiYLTiVBdRWtydL1qM_gVvcft1ak3SgEgNXkJt8
atR2cXFAKWdQajoKKxQ_Rr4cl_r6nybdGT6lxkX1jRT04Ac15TChroEn3rkQjt9-Q

Access Token Header

The header is eyJraWQiOiIyMDE5MDUxMyIsImFsZyI6IlJTMjU2In0. After decoding this with base64url, this translates to {"kid":"20190513","alg":"RS256"}.

kid is an identifier of a public key that can be used to validate the signature. alg describes a signature algorithm that was used for this token. RS256 is an asymmetric signature algorithm, i.e. for signing an access token. IBM Cloud IAM keeps a secret private key but publishes the public key for everyone. This way, every application and service can validate the signature locally without the help of an external system.

You can retrieve public keys for IBM Cloud IAM access tokens by querying the following keys endpoint: https://iam.cloud.ibm.com/identity/keys. For illustration, this is a current response of that endpoint:

{
"keys": [{
"kty": "RSA",
"n": "ugd1z...O1Q",
"e": "AQAB",
"alg": "RS256",
"kid": "20190724"
}, {
"kty": "RSA",
"n": "mrefG...OUw",
"e": "AQAB",
"alg": "RS256",
"kid": "20190513"
}, {
"kty": "RSA",
"n": "pJdNZ...qww",
"e": "AQAB",
"alg": "RS256",
"kid": "20190204"
}
]
}

Clients need to download that public key list and select the entry in the list that matches the access token’s kid property in the header to validate the signature. Public keys should be cached locally to reach the best performance and limit the load on the IAM servers. Repeated calls to the keys endpoint from the same IP address will be blocked by a rate limit component. I recommend a cache lifetime of an hour for a public key. If a certain key would ever be compromised, IBM Cloud IAM would remove that key from that list. Maintaining keys for just one hour is a good compromise of reducing requests against the IAM server for retrieving the public keys and reacting to potentially compromised keys. IBM Cloud rotates signature keys regularly — the exact frequency is not documented and is subject to be changed in the future.

Access Token Payload

The payload of the sample access token from above is

eyJpYW1faWQiOiJJQk1pZC0yNzAwKioqKjRYIiwicmVhbG1pZCI6IklCTWlkIiwiaWRlbnRpZmllciI6IjI3MDAqKioqNFgiLCJnaXZlbl9uYW1lIjoiTWFydGluIiwiZmFtaWx5X25hbWUiOiJTbW9sbnkiLCJuYW1lIjoiTWFydGluIFNtb2xueSIsImVtYWlsIjoiTWFydGluLlNtb2xueUBkZS5pYm0uY29tIiwic3ViIjoiTWFydGluLlNtb2xueUBkZS5pYm0uY29tIiwiYWNjb3VudCI6eyJ2YWxpZCI6dHJ1ZSwiYnNzIjoiOWJmKioqKjRkYTQqKioqZWIxMioqKio0YzZiKioqKjQiLCJpbXMiOjEyMzQ1NiwiaW1zX3VzZXJfaWQiOjk4NzY1NDMyfSwiaWF0IjoxNTY4NDk0NTUxLCJleHAiOjE1Njg0OTgxNTEsImlzcyI6Imh0dHBzOi8vaWFtLmNsb3VkLmlibS5jb20vaWRlbnRpdHkiLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJzY29wZSI6ImlibSBvcGVuaWQiLCJjbGllbnRfaWQiOiJieCIsImFjciI6MSwiYW1yIjpbInB3ZCJdfQ

After decoding this with the base64url algorithm, this translates to

{
"iam_id": "IBMid-2700****4X",
"realmid": "IBMid",
"identifier": "2700****4X",
"given_name": "Martin",
"family_name": "Smolny",
"name": "Martin Smolny",
"email": "Martin.Smolny@de.ibm.com",
"sub": "Martin.Smolny@de.ibm.com",
"account": {
"valid": true,
"bss": "9bf****4da4****eb12****4c6b****4",
"ims": 123456,
"ims_user_id": 98765432
},
"iat": 1568494551,
"exp": 1568498151,
"iss": "https://iam.cloud.ibm.com/identity",
"grant_type": "password",
"scope": "ibm openid",
"client_id": "bx",
"acr": 1,
"amr": ["pwd"]
}

The properties inside an access token are called claims. These are the supported claims and their meaning:

  • iam_id: Unique identifier inside IBM Cloud IAM denoting an identity. The iam_id is built using the realmid claim and the identifier claim, connected by a dash. IBM Cloud Services, and also IAM’s authorization system is referencing iam_id values. A user’s family name can change, e.g. caused by a marriage, also a user’s username that is used to log in — but the iam_id stays the same.
  • realmid: A unique identifier describing the source identity provider where the identity that was authenticated is managed. Well-known realmid values are IBMid for users managed by the IBMid system, SL for users managed by the former SoftLayer system, iam for Service Ids (details later), and crn for tokens that are used for service-to-service invocations.
    Be cautious about realmid values and do not make too tight validity checks — additional realmid values might show up in the future.
  • identifier: Identifier that uniquely identifies the identity inside the source identity provider that is identified by the realmidclaim. The actual claim value is dependent on the identity provider. In the case of IBMid , e.g. the IBMid Unique Identifier (IUI) from the IBMid system is used. This unique identifier must not change during the existence of that identity.
  • given_name, family_name, name, email: These claims can be used to display user-related information in a User Interface. There is no specific usage intended in IBM Cloud IAM for these claims.
  • sub: This claim contains the username of the identity. A username is typically required to authenticate. Other than the iam_id, the sub claim can change over time — this is different to the Open ID Connect standard. It is not safe to store the sub claim’s value for later references. Also, the sub claim is case insensitive, as some identity providers are not able to reliably provide usernames in the same case syntax.
  • account: This complex claim is only available if the access token was made account-specific. In a later story, I will explain how to make a token account-specific. The claim bss contains the selected billing account identifier, the claim ims contains the identifier of the related infrastructure account. Certain former SoftLayer APIs require an IMS user id as a parameter. Therefore, if an ims claim is present, you also get the claim ims_user_id which points to a SoftLayer API internal user id. The claim valid exists to distinguish between an older version of access tokens and the currently supported version of access tokens. If you rely on the claim ims and ims_user_id, make sure that the claim valid is set to true also, otherwise, the IMS-related information in the token are not validated.
  • iat & exp: These two claims indicate the date and time when the token was issued (iat) or will expire (exp). Both are a number representing the seconds from 1970–01–01T00:00:00Z in UTC.
  • grant_type: This claim describes the authentication mechanism that was used to retrieve this access token. Potential values are
    -password
    -implicit
    -authorization_code
    -urn:ibm:params:oauth:grant-type:passcode
    -urn:ibm:params:oauth:grant-type:apikey
    -urn:ibm:params:oauth:grant-type:iam-authz
    -urn:ibm:params:oauth:grant-type:ims-portal
  • scope: An arbitrary list of strings, delimited by a space, which lists capabilities of that token. In the OAuth 2.0 Authorization Framework, this claim contains the authorization information of that token.
    IBM Cloud IAM has a separate authorization component, but the scope claim still plays a role in the authorization decision. By intentionally selecting less powerful or subsets of scopes, you can limit the capabilities that this access token has without the need to update authorization policies. I will give an insight into details of the scope handling and also into the authorization component in one of the next stories.
  • client_id: The client_id claim indicates the client that was initiating the authentication process. Each application in OAuth 2.0 that is able to initiate the authentication process must pre-register a client id & secret with IBM Cloud IAM.
  • acr: This claim is the Authentication Context Class Reference and describes the level of assurance of the authentication. Currently, only level 1 and 2 are supported. Level 1 describes a normal authentication process either via User Interface or via password grant without any additional second-factor authentication (2FA) step. Level 2 additionally indicates that the identity provider has done a 2FA step, e.g. Time-based One Time Passcodes (TOTP). The most prominent application to support TOTP is the Google Authenticator.
  • amr: The Authentication Method Reference claim contains an array of authentication mechanisms like password , otp or totp. IBM Cloud IAM has chosen to follow the RFC 8176 Authentication Method Reference Values for the values.
  • iss: The issuer identifies the token system that was generating the token. The issuer depends on the endpoint that was used to generate the token.
    Potential values for the issuer are
    - https://iam.cloud.ibm.com/identity
    - https://iam.cloud.ibm.com/oidc
    - https://iam.bluemix.net/identity
    - https://iam.bluemix.net/oidc

The host part of the issuer is dependent on the hostname that was used to generate the token, i.e.

  • for the host part iam.cloud.ibm.com either the global endpoint https://iam.cloud.ibm.com or one of the regional endpoints like https://identity-1.us-south.iam.cloud.ibm.com was used
  • for the host part iam.bluemix.net either the global endpoint https://iam.bluemix.net or one of the regional endpoints like https://iam-id-1.ng.bluemix.net was used.

The context part of the issuer is dependent on the token endpoint that was used to generate the token, i.e.

  • for the context part identity the token endpoint /identity/token was used, e.g. https://iam.cloud.ibm.com/identity/token
  • for the context part oidc the token endpoint /identity/oidc was used, e.g. https://iam.cloud.ibm.com/oidc/token.

Access Token Lifetime

At the moment, access tokens have a fixed expiration of 3600 seconds / 1 hour starting at the time when the token was issued. Currently, there is no way to limit the expiration to a smaller value. In the future, this number can change to a smaller value. I do not expect that we would ever consider issuing access tokens that live longer than 3600 seconds.

Access Token Confidentiality

As the access token’s lifetime is limited by its expiration, the access token is used to authenticate a client to a server. This means access tokens may leave the client for API interactions. This is the intended use of access tokens.

Typically, the access token is sent to an API as an HTTP header. The header’s name is usually Authorization and the token itself is prefixed with Bearer. APIs can, of course, specify their own way to transmit the access token, but should avoid putting the access token’s value in the URL e.g. as a query parameter. This will likely make the access token show up in various logs and increase the probability that the access token can be leaked.

Refresh Token

Refresh tokens are required to re-generate an access token. Usually, they are used to refresh if the access token is expired. Nevertheless, there is no validation happening if the access token is already expired or not, i.e. you can use the refresh token any time you need to get a new access token — until the refresh token expires. A refresh token is bound to the client id that was used to create the refresh token, i.e. if you created the refresh token with client id clientA then the only client that can refresh an access token using that refresh token is client id clientA. Other clients are not allowed to use the refresh token.

Refresh Token Lifetime

When you originally authenticated to get a token, the refresh token was created with an expiration of 30 days. Whenever you use a refresh token to get a new set of access, refresh and ID token, the refresh token’s expiration is not extended, i.e. the new refresh token keeps the same expiration as the refresh token had that was used to do the refresh.

Refresh Token Confidentiality

Refresh tokens allow creating access tokens for up to 30 days. This also means, if a refresh token is leaked, then the attacker potentially can misuse the refresh token for up to 30 days.

To prevent leaking refresh tokens, it is strongly recommended that the refresh token never leaves the client — except for refreshing an access token.

ID Token

As mentioned before, ID tokens are only created if the token was requested by a client id that was configured to follow the Open ID Connect specification. Consequently, the ID token contains the same content as the access token plus all required claims that the Open ID Connect specification defines.

You cannot use ID tokens to invoke IBM Cloud services. ID tokens’ primary intent is the integration with tools and frameworks that require Open ID Connect compliant tokens and behavior. The integration of the IBM Cloud Kubernetes Service with IBM Cloud IAM, for example, requires such a client id, as the CNCF-driven Kubernetes API Server requires the Open ID Connect communication protocol.

Token Type, expires_in, expiration and scope response parameters

To ease the usage of access tokens for clients, the response parameters token_type , expires_in , expiration and scope contain key information that would be available inside the access token.

  • token_type is always set to Bearer
  • expires_in indicates the number of seconds when the access token and ID token will expire; at the moment, this will always be 3600, i.e. one hour. This value can change any time in the future.
  • expiration indicates the absolute time in seconds since January 1st 1970, 00:00:00 UTC when the access token and ID token will expire. This is an alternative way to expires_in and should return the equivalent result for the client.
  • scope will contain a space-separated list of scopes that this access token contains; most client ids will produce an access token with the scopes openid and ibm. The usage of scopes in IBM Cloud IAM will be explained in a later story in more detail.

UAA Token

Related response type: uaa

Required Additional Parameters: uaa_client_id , uaa_client_secret , optional uaa_redirect_uri , optional uaa_scope

One common use case for UAA tokens is if clients of IBM Cloud plan to use public CloudFoundry’s API ( see also https://apidocs.cloudfoundry.org ).

UAA tokens can be retrieved at the same time when the access token is retrieved — add the response type uaa space separated to the response_type parameter. The overall token retrieval will be slower, as the overall response needs to wait on the interaction from the IBM Cloud IAM Identity Service to public CloudFoundry.

Alternatively, you can issue a separate call to the token endpoint with grant_type=urn:ibm:params:oauth:grant-type:derive and provide the previously retrieved access token. This variation allows you to move the call to retrieve a UAA token into the background, making your client application more responsive.

Additional Parameters for UAA tokens

The administrators of public CloudFoundry must provide you a valid client_id/client_secret pair for the target environment. Use this pair as uaa_client_id and uaa_client_secret. Only IBM Cloud Service providers can get those credentials.

If the interaction to get the IBM Cloud IAM access token did involve a UI login, the optional parameter uaa_redirect_uri is required. The URL does not need to match any real URL, it is simply needed to match whatever your client id in public CloudFounrdy is white-listing in its settings.

Independent from the interaction, the parameter uaa_scope allows you to limit the resulting scopes of a UAA token.

UAA refresh token

To support some edge cases, the UAA token is accompanied by a corresponding UAA refresh token. Usually, you can use the IBM Cloud IAM refresh token to get a new IBM Cloud IAM access token and UAA token. Therefore, if you do not have a specific reason, you should ignore the UAA refresh token.

If for any reason you need the UAA refresh token, then the same rules apply to that UAA refresh token like for the IBM Cloud IAM refresh token:

  • store the UAA refresh token safely on the client
  • do not send the UAA refresh token to service APIs
  • the only reason why the UAA refresh token might leave the system is when the UAA refresh token is used to get a new UAA token; in that case, make sure to only send the UAA refresh token to either the token or authorization endpoint of public CloudFoundry

IMS Token

Related response type: ims_portal

Required Additional Parameters: none

If you plan to invoke former SoftLayer APIs ( see https://sldn.softlayer.com/reference/services ), you can use the IMS Token to authenticate the call. Getting an IMS Token is only possible if an account was selected before or within this token call, as IMS Tokens are always account-specific and are valid only within one specific infrastructure account.

Like with UAA tokens, you can retrieve an IMS token at the same time as the access token. Do this by adding the parameter ims_portal in the response_type parameter list. Also here, the overall token retrieval will be slower, as the overall response needs to wait on the interaction from the IBM Cloud IAM Identity Service to the IBM Cloud Infrastructure Service (former known as SoftLayer).

Alternatively, you can issue a separate call to the token endpoint with grant_type=urn:ibm:params:oauth:grant-type:derive and provide the previously retrieved access token. This variation allows you to move the call to retrieve an IMS Token into the background, making your client application more responsive.

Together with the IMS token, you also get an IMS User Id. This is an internal user identifier that is required for some API calls, see e.g. https://sldn.softlayer.com/reference/services/SoftLayer_User_Customer/getObject/ .

Identity Cookie

Related response type: identity_cookie

Required Additional Parameters: none

When an end-user is logging in with its browser using IBM Cloud IAM, an identity cookie is set to the browser. This prevents the user from being forced to re-authenticate in the same browser session if e.g. another browser tab or frame inside the browser session requires IBM Cloud IAM authentication also. The cookie is set with the following properties:

  • HTTPOnly, i.e. no JavaScript code inside the browser must have access to the cookie
  • Secure, i.e. only https connections will transmit this cookie
  • Domain bluemix.net or cloud.ibm.com , dependent which domain was used to initially log in

UI Services that run in the same domain, i.e. bluemix.net or cloud.ibm.com , get this identity cookie sent from the browser. These UI services now can use the grant type urn:ibm:params:oauth:grant-type:identity-cookie to directly get a token without the need to do a “OAuth Dance”, i.e. without the need to forward the browser to the authorization endpoint of IAM.

What is the reason for the identity cookie as response type? This feature is intended to allow test automation for UI Services, i.e. test cases can retrieve an identity cookie based on a username / password combination or an API key, and then they can invoke UI services with the identity cookie that was retrieved programmatically.

In IBM Cloud public, no client id has the authorization to request this response type. This response type is used in test and pre-production environments.

Delegated Refresh Token

Related response type: delegated_refresh_token and iam_cookie

Required Additional Parameters: receiver_client_ids anddelegated_refresh_token_expiry

If you paid attention to this story so far, you learned that you never ever give away a refresh token. They must stay on your service and only be used to refresh an access token.

Now, I am showing two variations of a refresh token that is intended to be shared: the delegated refresh token / the iam cookie

Both have similar behavior, but the iam cookie is the older, less powerful and deprecated variation, therefore I will only describe the delegated refresh token.

In one of the next stories, I will show scenarios that can be solved with the delegated refresh token. For the moment, it is important to understand that

  • a delegated refresh token contains the same information like a refresh token
  • only client ids that are listed in the receiver_client_ids list are able to receive and use that type of token
  • to use the delegated refresh token, the receiver must provide its client id/client secret combination to the IBM Cloud IAM service
  • after receiving the delegated refresh token, it contains the same information and expiration that was contained before in the token that was used to generate the delegated refresh token

What’s next?

Now that you have an overview of the different token types that IBM Cloud IAM can provide, I will show the different grant types to authenticate and so generate an IBM Cloud IAM access token. The next story will show you all the potential ways to generate tokens “programmatically”.

If you have comments, questions, or want to see a specific topic being covered in one of the next stories, please leave a comment or contact me. Your feedback is welcome!

Martin Smolny

Written by

Martin Smolny is a Software Engineer and Architect at IBM. He is responsible for authentication in the IBM Cloud Platform.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade