Flows

Both OAuth 2.0 and OpenID Connect have defined a few authentication flows for different kind of scenarios and client applications. OpenID Connect defines three types of flows and all of them are supported in Unit4 Identity Services:

In addition, Unit4 Identity Services (U4IDS) also supports two more flows defined by OAuth 2.0:

There is also an addition to the Authorization code flow called Proof key for code exchange (PKCE, pronounced Pixy)

Which flow to use?

When choosing the authentication flow to use, it is important to understand:

U4IDS supports all these flows but we recommend using client credentials for machine to machine communication and Auth Code with PKCE for all user centric scenarios.

Note

The resource owner password grant flow (defined by OAuth 2.0) is not supported by U4IDS.

The table below provides guidance on which flow to choose in particular contexts.

Property Implicit flow Authorization code flow Hybrid flow Client credential flow
Client can be authenticated No Yes Yes Yes
Suitable for confidential clients Yes Yes Yes Yes
Suitable for public clients Yes Yes* No No
Refresh token possible No Yes Yes No
Communication in one roundtrip Yes No No Yes
Tokens revealed to User Agent Yes No Yes No

*With PKCE

Client credential flow

This flow is suitable for machine-to-machine authentication, for example for use in a scheduled job which is performing maintenance tasks over an API. Another example would be a piece of software making requests to an API that does not require user permission.

In the client credentials flow, the authentication would rely on a (shared) secret as the means of authentication. The client secret will be registered with U4IDS and known to the client. The shared secret will be sent to U4IDS during an authentication request to obtain an access token. In the authentication request the client will also need to specify what scopes (resources) it needs access to.

Step 1. - Request access token Client requests a response using the secret at the Token Endpoint.

Example token request

POST /token

grant_type=client_credentials&client_id=<client_id>&client_secret=<secret>&scope=<scope>

Parameter name Description
grant_type Specifies that client credentials are used to obtain access token..
client_id The unique identifier of the client application.
client_secret The shared client secret.
scope The resource scopes identifying resource servers.

Step 2. - Token response

Client receives a response that contains the access token.

Step 3. - Request resource

The client requests the resource from the protected resource server. The client uses the Access token that includes the scope defined in the token request.

Authorization code flow

The Authorization Code Flow is intended for clients that can securely maintain a Client Secret between themselves and the U4IDS. See confidential clients for details.

The authorization code flow returns an authorization code that can then be exchanged for an ID token and access token. This requires client authentication using a client ID and secret to retrieve the tokens from the back-end and has the benefit of not exposing tokens to the User Agent. This flow allows for long lived access (through the use of refresh tokens). This flow obtains the authorization code from the Authorization Endpoint and all tokens are returned from the Token endpoint.

This mechanism was originally designed for server-based applications only, since storing client secrets on a client device is dubious without the correct security mechanisms in place.

Authorization code flow steps

Step 1. - Authorize request

The client prepares an Authentication Request containing the desired request parameters and sends the request to the U4IDS authorize endpoint.

Authorize request example


GET /connect/authorize?client_id=<id>&scope=<scope>&acr_values=tenant:<tenantID>&response_type=code&redirect_uri=<uri> HTTP/1.1
Host: server.example.com
Accept: application/json

The following properties are available for the authorization request:

Parameter name Description
client_id (required) The identifier for the client registered.
scope (required) The name of the scope for the resource server to access. openid scope is required. To access a resource server you should also provide the scope for the resource server.
response_type (required) Valid value for code flow is code.
redirect_uri (required) The client uri of where to redirect when authentication is done. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of [RFC3986] (Simple String Comparison). When using this flow, the Redirection URI MUST NOT use the http scheme unless the Client is a native application, in which case it MAY use the http: scheme with localhost as the hostname.
tenant (required) The identifier of the tenant that specifies the authentication. The tenant id is specified via the acr-values parameter, on this format tenant:tenant_id.
loginidp The identifier of a Identity Provider that is about to authenticate the user (see above).
response_mode Specifies how the token is returned back to the client. Default for this flow is fragment. See Response types and Response modes
nonce (optional) String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values. For implementation notes, see Section 15.5.2.
state(recommended) Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.
login_hint Hint to the Authorization Server about the login identifier the End-User might use to log in.
prompt Specifies whether the Authorization Server prompts the End-User for reauthentication and consent, see above.

Step 2. - Authentication

Since U4IDS is a federated gateway with no user repository, the authentication occurs on the tenant's identity provider (external IdP). U4IDS looks up the tenant ID from the acr_values on the authorize request and finds the tenant's identity provider and redirects for authentication.

Step 3. - Code response

The authorization code flow returns an authorization code via the user agent (unauthenticated front channel, such as an embedded browser window).

Step 4. - Request token

The client requests a response using the Authorization Code at the Token Endpoint. This requires client authentication using client ID and secret (or some other mechanism) to retrieve the actual tokens (including a refresh token) via the back channel, confidential client. If the user has consented to offline_access scope the token response will also contain a refresh token. The refresh token can be used to exchange for a new access token when an access token has expired.

Request access token

Example token request using credentials (client_id and client secret) in body

POST /token

code=<code>&grant_type=authorization_code&client_id=<client_id>&client_secret=<secret>

An alternative authentication method is sending a JWT token with X509 certifcate in client_assertion parameter accompanied by client_assertion_type, see private_key_jwt in OpenID Connect specs. In this method the thumbprint of a certificate added to the header of JWT token has to be stored as client secret in IDS and be of Type X509Thumbprint. client_id & client_secret should not be passed in this case.

Parameter name Description
code The authorization code obtained from in the previous step.
grant_type authorization_code specifies that a authorization code is used to obtain tokens. refresh_token specifies that refresh token is used to obtain a new token.
client_id The unique identifier of the client application.
client_secret The shared client secret.
redirect_uri Although tokens are sent back as response content (not sent to "redirect uri") this parameter is required and must be registered in IDS as a client's valid redirect URI.
client_assertion a serialized JWT token.
client_assertion_type must be 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
Request refresh token

Example of a refresh token request

POST /token

refresh_token=<refresh_token>&grant_type=refresh_token&client_id=<client_id>&client_secret=<client_secret>&scope=<scope>

Parameter name Description
refresh_token The refresh token stored in .
grant_type refresh_token specifies that refresh token is used to obtain a new token.
client_id The unique identifier of the client application.
client_secret The shared client secret.

Step 5. - Token response

The client receives a response that contains an ID Token and Access Token in the response body.

Step 6. - Request resource

The client requests the resource from the protected resource server. The client uses the Access token.

Example request a resource with the access token

GET  /api/<resource>
Host: server.example.com
Accept: application/json
Authorization: Bearer <Access token>

Step 7. - Token validation

The resource server validates the tokens for signature, expected issuer name, expected audience or scope.

Step 8. - Resource response

If token validation success the resource server sends the requested resource back to the client.

See code flow specification for details.

Authorization code flow with PKCE

The Authorization Code Flow + PKCE is an OpenId Connect flow specifically designed to authenticate native or mobile application users.

PKCE, pronounced “pixy” is an acronym for Proof Key for Code Exchange. The key difference between the PKCE flow and the standard Authorization Code flow is users aren’t required to provide a client_secret. PKCE reduces security risks for native apps, as embedded secrets aren’t required in source code, which limits exposure to reverse engineering.

Steps

In place of the client_secret, the client app creates a unique string value, code_verifier, which it hashes and encodes as a code_challenge. When the client app initiates the first part of the Authorization Code flow, it sends a hashed code_challenge. Once the user authenticates and the authorization code is returned to the client app, it requests an access_token in exchange for the authorization code. In this step, the client app must include the original unique string value in the code_verifier parameter. If the codes match, the authentication is complete and an access_token is returned.

You dont need to have a secret in this flow, but if a secret is added to the client then it must be provided during authorization.

Implicit flow

In Implicit flow the ID token and access token are directly returned to the client. When using the implicit flow, the server does not perform client authentication. This flow is mainly used by web browser client-side rendered applications (such as a JavaScript client).

The implicit flow requests tokens without explicit client authentication, instead using the redirect URI to verify the client identity. Because of this, long lived tokens are not allowed. This is the simplest flow to implement as it only needs to redirect to the user the location of the OIDC provider. This flow obtains all of its tokens from the Authorization endpoint.

Steps

In the scenario where a client is using an access token to access resources on ANOTHER server (the Resource Server), the RS must lookup attributes of the access token with the issuer. How to include that token as part of a request for a protected resource and how the protected resource can check the token is described below. The figure below shows the steps for an implicit authentication flow done in U4IDS.

Step 1. - Authorize request

The client prepares an Authentication Request containing the desired request parameters and sends the request to the U4IDS authorize endpoint.

Authorize request example


GET /connect/authorize?client_id=<id>&scope=<scope>&acr_values=tenant:<tenantID>&response_type=id_token%20token&redirect_uri=<uri> HTTP/1.1
Host: server.example.com
Accept: application/json

For the authorize request the following properties are available:

Parameter name Description
client_id (required) The identifier for the client registered.
scope (required) The name of the scope for the resource server to access. openid scope is required. To access a resource server you should also provide the scope for the resource server.
response_type (required) Specifies the type of token to receive. Valid values for implicit flow are token, id_token and id_token token. NOTE: While OAuth 2.0 also defines the token Response Type value for the Implicit Flow, OpenID Connect does not use this Response Type, since no ID Token would be returned.
redirect_uri (required) The client uri of where to redirect when authentication is done. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of [RFC3986] (Simple String Comparison). When using this flow, the Redirection URI MUST NOT use the http scheme unless the Client is a native application, in which case it MAY use the http: scheme with localhost as the hostname.
tenant (required) The identifier of the tenant that specifies the authentication. The tenant id is specified via the acr_values parameter, on this format tenant:tenant_id.
loginidp The identifier of a Identity Provider that is about to authenticate the user. The identifier must match the value of the IdpName attribute of the tenant specified in the request (see above). The loginidp is specified via the acr_values parameter with the following format loginidp:IdpNameValue with space as the separator between tenant and loginidp parameters.
response_mode Specifies how the token is returned back to the client. Default for this flow is fragment. See Response types and Response modes
nonce (required) String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values. For implementation notes, see Section 15.5.2.
state (recommended) Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.
login_hint Hint to the Authorization Server about the login identifier the End-User might use to log in.
prompt Specifies whether the Authorization Server prompts the End-User for reauthentication and consent, see Authentication Request. 'login' value can be very useful to reauthenticate the user with a different tenant (get a new id token) while opening a new browser's tab - otherwise the current session will be used. 'select_account' is not supported by IDS. 'consent' does not raise error when a consent has not been given.

Step 2. - Authentication

Since U4IDS is a federated gateway with no user repository, the authentication happens on the tenant's identity provider (external IdP). U4IDS looks up the tenant ID from the acr_values on the authorize request and finds the tenant's identity provider and redirects for authentication.

Step 3. - Token response

U4IDS sends the end user back to the Client with an ID Token and, if requested, an Access token.

Step 4. - ID Token validation

The client validates the ID token and retrieves the end user's Subject Identifier.

Step 5. - Request resource

The client requests the resource from the protected resource server. The client uses the Access token.

Example request a resource with the access token

GET  /api/<resource>
Host: server.example.com
Accept: application/json
Authorization: Bearer <Access token>

Step 6. - Access Token Validation

The resource server validates the tokens for signature, expected issuer name, expected audience or scope.

Step 7. - Resource response

If token validation is successful, the resource server sends the requested resource back to the client.

See implicit flow specification for details.

Hybrid flow

The hybrid flow combines aspects of the Authorization Code Flow and the Implicit Flow. It allows to request a combination of identity token, access token and code via the front channel using either a fragment encoded redirect (native and JS based clients) or a form post (server-based web applications). This enables, for example, scenarios where your client app can make immediate use of an identity token to get access to the user’s identity but also retrieve an authorization code that that can be used (for example by a backend service) to request a refresh token and thus gain long lived access to resources. It enables clients to obtain an ID Token and optionally an Access Token with only one round trip to U4IDS, possibly minimizing latency, while still enabling clients for long lived access. Tokens can be obtained later from the token endpoint again through the use of refresh tokens.

Hybrid flow steps

Step 1. - Authorize request

The client prepares an Authentication Request containing the desired request parameters. Note that the response type must be code combined with some other response type, for example id_token or token (or both). The client sends the request to U4IDS.

Authorize request example

GET /authorize?response_type=code%20id_token&client_id=<client_id>&redirect_uri=<redirect_uri>&scope=<scope>&acr_values=tenant:<tenantID> HTTP/1.1
Host: server.example.com
Accept: application/json

For the the authorize request the following properties are available:

Parameter name Description
client_id (required) The identifier for the client registered.
scope (required) The name of the scope for the resource server to access. openid scope is required. To access a resource server you should also provide the scope for the resource server.
response_type (required) OAuth 2.0 Response Type value that determines the authorization processing flow to be used, including what parameters are returned from the endpoints used. When using the Hybrid Flow, this value is code id_token, code token, or code id_token token.
redirect_uri (required) The client uri of where to redirect when authentication is done. Redirection URI to which the response will be sent. This URI MUST exactly match one of the Redirection URI values for the Client pre-registered at the OpenID Provider, with the matching performed as described in Section 6.2.1 of [RFC3986] (Simple String Comparison). When using this flow, the Redirection URI MUST NOT use the http scheme unless the Client is a native application, in which case it MAY use the http: scheme with localhost as the hostname.
tenant (required) The identifier of the tenant that specifies the authentication. The tenant id is specified via the acr_values parameter, on this format tenant:tenant_id.
loginidp The identifier of a Identity Provider that is about to authenticate the user (see above).
response_mode Specifies how the token is returned back to the client. Default for this flow is fragment. See Response types and Response modes
nonce (optional) String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values. For implementation notes, see Section 15.5.2.
state(recommended) Opaque value used to maintain state between the request and the callback. Typically, Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the value of this parameter with a browser cookie.

Step 2. - Authentication Since U4IDS is a federated gateway with no user repository, the authentication occurs on the tenant's identity provider (external IdP). U4IDS looks up the tenant ID from the acr_values on the authorize request and finds the tenant's identity provider and redirects for authentication.

Step 3 - Authentication response When using the Hybrid Flow, Authentication Responses are made in the same way as for the Implicit Flow. Based on the response_type parameter, the authentication response can contain id_token or access_token or both. The authorization code is always returned using the hybrid flow.

Step 4. - Request tokens The client requests a response using the Authorization Code at the Token Endpoint. This requires client authentication using client ID and secret (or some other mechanism) to retrieve the actual tokens (including a refresh token) via the back channel, confidential client.

Example token request

POST /token

code=<code>&grant_type=authorization_code&client_id=<client_id>&client_secret=<secret>

Parameter name Description
code The authorization code obtained from in the previous step.
grant_type Specifies that a authorization code is used to obtain tokens.
client_id The unique identifier of the client application.
client_secret The shared client secret.

Step 5. - Token response

The client receives a response that contains tokens. The tokens received are dictated by the response_type in the authentication request. If the client has requested access to the offline_access scope, the server responds with a refresh token.

Step 6. - Request resource

The client requests the resource from the protected resource server. The client uses the Access token.

Example request a resource with the access token

GET  /api/<resource>
Host: server.example.com
Accept: application/json
Authorization: Bearer <Access token>

Step 7. - Token validation

The resource server validates the tokens for signature, expected issuer name, expected audience or scope.

Step 8. - Resource response

If token validation success the resource server sends the requested resource back to the client.

See hybrid flow specification for details.

User impersonation custom flow

This flow is suitable for resource APIs that need to call another API on behalf of the user. This scenario involves a normal client application that authenticates the user using any of the standard flows, and at least two APIs where one needs to call another at some point. The caller API needs to use "user_impersonation" flow to access the called API, with an access code obtained by the normal client application.

User impersonation flow steps

Step 1-3 - Client application authentication

User impersonation flow is different from the previous standard flows in that it involves more than one client application and more than one resources. As shown in the diagram, both the client application and WebAPI1 are registered clients to U4IDS, and both WebAPI1 and WebAPI2 are registered resource scopes. The key part of this flow is about one downstream client (here the WebAPI1 which is also a resource) accesses another resource on behalf of the user. As to the initial authentication of the client application, it can use any of the standard flows. This is not the focus of the user impersonation flow.

Step 4 - Client application request resource 1

The client requests the resource WebAPI1 from the protected resource server. The client uses the Access token obtained from authentication. This step is the same as in implicit/ authorization code /hybrid flows. Not to repeat the details here.

Step 5 - Request (delegated) access token

The WebAPI1 resource requests an access token on behalf of the user at the Token Endpoint. This request uses the user_impersonation custom grant and sends in the forwarded access token, the resource scope ID to be accessed, and the client ID and secret to perform an authentication for WebAPI1 client. If authenticated, U4IDS responds with a new access token granted to WebAPI1 to access WebAPI2 only. In this process the custom grant validator will check if the user has given consent to the requested scopes. As no user interaction is possible in this step, any scopes that has not been consented will not be returned in the token.

Example token request

POST /token

token=<token>&grant_type=user_impersonation&client_id=<client_id>&client_secret=<secret>&scope=<scope>

Parameter name Description
token The token forwarded from client application in the request.
grant_type Specifies that the user_impersonation custom grant is used to obtain tokens.
client_id The unique identifier of the client application WebAPI1
client_secret The shared client secret of WebAPI1
scope The scope id of WebAPI2

Step 6 - Delegate token response

The client WebAPI1 receives a response that contains token to access the specified resource scope WebAPI2 only.

Step 7 - Request resource WebAPI2

The client WebAPI1 requests the resource WebAPI2 from the protected resource server 2. The client uses the access token obtained from step 6.

Step 8 - Access Token Validation

The resource server validates the tokens for signature, expected issuer name, expected audience or scope.

Step 9 - Resource WebAPI2 response

If token validation is successful, the resource server 2 sends the requested resource back to the client WebAPI1.

Claims upgrade custom flow

This flow can be used in combination with human involved flows, when we would like to add additional claims to an access token previously obtained by U4IDS. Given an existing resource server that has additional information about an identified user, this resource server can use the claims upgrade custom flow to ensure that the additional information is added to the access token. This upgraded access token can be used to call another API, by this eliminating an extra round-trip to the resource server. In the examples below we will provide a scenario that uses the claims upgrade flow.

Claims upgrade custom flow steps

Step 1-3: Client application authentication

Client application uses one of the human involved flow to identify the user and request an access token that can be used with both Resource Server 1 and Resource Server 2. For details please consult the information written above.

Step 4: Client application request claims upgrade from Resource Server 1

Client application calls endpoint on Resource Server 1, providing the access token received on step 3. The resource server identifies the user, looks up the additional information regarding this user.

Step 5: Resource Server 1 request token from U4IDS

Resource Server 1 initiates the claims upgrade custom flow, providing any additional information that needs to add as claims. This is done by posting to the token endpoint from U4IDS, using the claims_upgrade custom grant and providing the original access token, the additional claims to be added, the scope defined for this type of claims upgrade, and the client and secret that protects this flow.

Example token request

POST /token

token=<token>&grant_type=claims_upgrade&client_id=<client_id>&client_secret=<secret>&scope=<scope>&<claimName>=<claimvalue>

Parameter name Description
token The token forwarded from client application in the request.
grant_type Specifies that the _claims_upgrade_ custom grant is used to obtain tokens.
client_id The unique identifier of the client application Resource Server 1
client_secret The shared client secret of Resource Server 1
scope The scope id defined for this type of upgrade
claimName The claim name to be used for upgrading the original token
Notes:
  1. The client identified by <client_id> needs to be defined as a custom flow, providing claims_upgrade for the allowedCustomGrantTypes
  2. U4IDS will check that <claimName> is a claim defined on the provided <scope>
  3. We might have multiple <claimName> / <claimValue> pairs
  4. Should we have several values for the same <claimName>, we have to provide these values in the <claimValue>, separated with space.
  5. <claimValue> will be treated as string and added accordingly to the claims of the newly generated token.

Step 6: U4IDS returns the upgraded access (and if requested refresh) token

Step 7: Resource server returns the upgraded access (and if requested refresh) token to the client application

Step 8: Client application calls Resource Server 2 hosting the WebAPI services

If token validation is successful, Resource Server 2 will also trust the values from the additional claims.