OAuth Flows

The OAuth protocol uses different flows to to setup tokens, as well as different ways how tokens can be used. This chapter is a summary of the different flows that establish Access Tokens, in relation to the Curity Identity Server. The actors that are used, are the Resource Owner (RO), the Client (C), the Resource Server (RS) and the Authorization Server (AS).

The full specification of OAuth is in RFC 6749.

Code

The Code flow is about a Resource Owner that authorizes an access request from the Client with the Authorization Server, resulting in a code that represents that delegated authorization. The user hands over the code to the Client, that uses it on a backchannel with the Authorization Server to exchange it for an OAuth Access Token.

This flow uses two endpoints on the Authorization Server, the oauth-authorize and the oauth-token endpoint.

It is split in two separate requests. The first is done in the front-channel in the browser as a regular GET request to the oauth-authorize endpoint.

GET request parameters:

Attribute Required Default value Description
scope No No Scope The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
state No No State The state will be returned in the final redirect
response_type Yes None Must be set to code
client_id Yes None The client id of the requestor.
redirect_uri Maybe   If only one redirect_uri is configured on the client this is not required if the openid scope is _not_ included. Otherwise it should be given.
code_challenge Maybe None The proof key code challenge. A client can be configured to require this attribute.
code_challenge_method No plain The method used to transform the code verifier into the code challenge. Supported values are plain and S256.

The second request is done as a server-side POST request with the content type application/x-www-form-urlencoded to the oauth-token endpoint. In this call the client needs to authenticate itself using its client credentials.

POST request parameters

Attribute Required Default value Description
scope No No Scope The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
grant_type Yes None Must be set to authorization_code
code Yes None The authorization code retrieved in the first call to the server.
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used
redirect_uri Maybe   If the redirect_uri parameter was given in the GET request, it must also be given here.
code_verifier Maybe None The proof key code verifier used to generate the code challenge (using the code challenge method) sent in the authorization request. Required, if a code_challenge was sent in the authorization request.

Proof Key for Code Exchange

OAuth public clients are susceptible to the authorization code interception attack (RFC 7636).

In this attack, the attacker intercepts the authorization code returned from the authorization endpoint within a communication path not protected by Transport Layer Security (TLS), such as inter-application communication within the client’s operating system; e.g. custom protocol handlers. Once the attacker has gained access to the authorization code, it can use it to obtain the access token.

To mitigate this attack, a unique “code verifier” is created client-side for every authorization request; which is transformed into a “code challenge” that is sent to the authorization server. The authorization code obtained is then sent to the token endpoint together with the “code verifier”, where it is compared with the previously received “code challenge”; performing proof of possession of the “code verifier” by the client.

Implicit

The Implicit flow is also about the Resource Owner authorizing the access request from the Client with the Authorization Server, like the Code flow, but it does not respond with a code, but instead it provides the OAuth Access Token directly.

This flow is optimized for JavaScript-based Clients, and uses only the oauth-authorize endpoint on the Authorization Server.

The implicit flow is available on the oauth-authorize endpoint and is accessed with a GET request in the browser. The following request parameters are supported in the query string:

Attribute Required Default value Description
scope No No Scope The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
state No No State The state will be returned in the final redirect
response_type Yes None Must be set to token
client_id Yes None The client id of the requestor.
redirect_uri Maybe   If only one redirect_uri is configured on the client this is not required. Otherwise it should be given.

The response is given as a fragment parameter in a redirect back to the client on a predefined or whitelisted redirect uri.

Client Credentials

In case a Client needs an OAuth Access Token, the Client Credentials flow allows an OAuth Client to make an authenticated request on the token endpoint to request an Access Token. Authentication is based on the Client Secret. There is no user authenticated in this flow, which makes it suitable for server to server communication only.

The client credentials flow is available on the oauth-token endpoint and is accessed with a POST and the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
scope No No Scope The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
grant_type Yes None Must be set to client_credentials
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used

Resource Owner Password Credentials

Mainly for supporting legacy applications, the Resource Owner Password Credentials flow allows an OAuth Client to provide the Resource Owner’s password credentials to the Authorization Server. The AS authenticates both the RO as well as the Client, and issues an OAuth Access Token on success. This flow has the undesired effect that the RO’s credentials are exposed to the OAuth Client.

The resource owner password credentials flow is available on the oauth-token endpoint and is accessed with a POST and the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
scope No No Scope The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
grant_type Yes None Must be set to password
username Yes None The username of the user to authenticate
password Yes None The password of the user to authenticate
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used

OpenID Connect Hybrid Flows

OpenID Connect defines hybrid flows which consists of combinations of (some of) the regular OAuth2 / OpenID Connect flows. To allow this, no extra configuration is needed other than having OpenID Connect enabled on the profile as well as the openid scope granted (and requested) for the client.

As an example, a grant_type could with a hybrid flow allow both code, token and even id_token to be asked for in the same request. This allows for some interesting, albeit not too common, flows for clients that need some data delivered on the front end channel, while still having the capability to retrieve other information from the backend (i.e. can keep a secret). See Hybrid Capabilities on the clients configuration page for more info.

Attribute Required Default value Description
scope Yes No Scope The scopes to include in the token. Must include openid for hybrid flow. Must be a subset of the scopes configured on the client.
state No No State The state will be returned in the final redirect
response_type Yes None Any combination of token, code and id_token.
client_id Yes None The client id of the requestor.
redirect_uri Yes   For OpenID Connect flows, the redirect_uri is always required.
nonce Maybe None Required for id_token. Will be visible in the ID token claims.

OpenID Connect CIBA Flow

Client Initiated Backchannel Authentication (CIBA) is an OpenID Connect authentication flow in which Relying Parties (RP), that can obtain a valid identifier for the user they want to authenticate, will be able to initiate an interaction flow to authenticate their users without having end-user interaction from the consumption device.

In order to be able to use back-channel authentication, an endpoint of type oauth-backchannel-authentication needs to be configured in the Token Service profile.

Back-channel Authenticators of supported types needs to be created in Authentication profile under the Back-channel Authenticators section of the admin UI. Depending on the authenticator type, the back-channel authenticator can have its own settings or optionally link to a front-channel authenticator in the same plugin group to re-use its settings and managed objects.

If multiple back-channel authenticators are configured, then back-channel authentication will be attempted on all of them for a request to start back-channel authentication. If required, it can be limited by specifying acr_values in the request.

Back-channel authentication can be enabled or disabled using admin UI under Capabilities section of Client Settings in Token Service profile. In addition, the following settings can also be configured.

Setting Default value Description
Request Time to Live 900 Number of seconds a back-channel authentication request is valid. This can be overridden by requested_expiry request parameter.
Must Sign Request Object False Enables mandatory signed request object for back-channel authentication. This must be set to true to comply with FAPI. As a prerequisite, Request Object JWT should be enabled and Signature Verification Key should be configured in the Advanced section of the client config.
Binding Message Max Length 10,000 The maximum number of characters allowed in binding_message.

Authentication can be initiated by the client by making a HTTP POST request to the configured back-channel endpoint with the below parameters. Upon successful initiation, the response would contain auth_req_id that corresponds to the CIBA Authentication request. Any additional parameters provided will be ignored by the server for the authentication request, however they are available for inspection in back-channel token procedure and can be included in the tokens, if required.

Parameter Required Default value Description
scope Yes No Scope The scopes to include in the token. Must include openid. Must be a subset of the scopes configured on the client.
acr_values No None Space-separated string of Requested Authentication Context Class Reference values.
login_hint Yes None Hint regarding the end-user for whom authentication is being requested.
binding_message No None A human readable message intended to be displayed on both the consumption device and the authentication device to interlock them together for the transaction by way of a visual cue for the end-user
requested_expiry No None Number of seconds in which the authentication request would expire.
id_token_hint No None Not supported currently.
login_hint_token No None Not supported currently.
user_code No None Not supported currently.
client_notification_token No None Not supported currently.

Currently, the Curity Identity Server supports only poll mode to get authentication result as specified in section 5 of the CIBA spec. The token can be obtained by making a poll request to the token endpoint using HTTP POST with below parameters. The poll request may be repeated until success or error for a period mentioned as expires_in in the initiation response at an interval specified by interval value.

Parameter Required Default value Description
grant_type Yes None Must be urn:openid:params:grant-type:ciba
auth_req_id Yes None The unique identifier from the response of the initial authentication request.

Signed Authentication Request

A signed authentication request can be made by encoding all of the authentication request parameters as claims of a signed JWT with each parameter name as the claim name and its value as a JSON string. The JWT must contain all of the authentication request parameters and be signed with asymmetric signing algorithm. The signed authentication request JWT should be passed as an application/x-www-form-urlencoded HTTP request parameter with the name request. The signing key for signed requests, is either statically configured as request-object configuration for a client, or taken from the jwks_uri in case of a dynamically registered client.

Token Exchange

The token exchange flow is a non-standard flow, that a Client can use to exchange an existing Access Token for a new Access Token. This new Access Token’s properties are limited to the original Access Token’s properties.

The purpose is to create a token that is a subset of the original token. Thus the new token cannot contain more authorization than the original token. This operation is typically referred to as downscoping. Two things can be downscoped:

  • Audience
  • Scopes

Thus, the token returned from the endpoint contains fewer audiences and fewer scopes than the original token.

The client needs to have the token-exchange capability enabled to be allowed to use this flow, and the client needs to authenticate (i.e. using Client Authentication).

Token exchange is initiated by the Client making a call to the oauth-token endpoint of the OAuth profile, using the grant_type https://curity.se/grant/accesstoken.

The request is a POST to the oauth-token endpoint with the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
scope Yes None The scopes, space separated, to include in the token. Must be a subset of the scopes configured on the client.
audience No Unchanged The audiences, space separated, to remove from the token
grant_type Yes None Must be set to https://curity.se/grant/accesstoken
token Yes None The token to downscope
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used.

The token exchange flow is available on the oauth-token endpoint.

Important

The grant-type to use for the token exchange flow is https://curity.se/grant/accesstoken

Assisted Token

The assisted token flow is a non-standard flow that a client can use to setup a new Access Token. This flow is particularly well suited to integrate in client side web applications, and is aimed to make integrating token setup as easy as possible.

The client needs to have the assisted-token capability enabled to be allowed to use this flow.

The assisted token flow is available on the oauth-assisted-token endpoint. For more information about the assisted flow see the assisted token api.

Refresh

The refresh flow is used to exchange a refresh token for a new access token and refresh token pair. If reuse-refresh-token is set in the authorization server configuration or client configuration, only an access token will be returned.

The refresh token flow is available on the oauth-token endpoint and is accessed with a POST and the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
scope No Unchanged The scopes, space separated, to include in the token
grant_type Yes None Must be set to refresh_token
refresh_token Yes None The refresh token
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used.

The time validity of refresh tokens is defined by two configuration settings:

  • refresh-token-ttl - defines the time to live of each individual refresh token. If set to disabled, no refresh tokens will be issued.
  • refresh-token-max-rolling-lifetime - defines the time interval on which new refresh tokens can be obtained (via a refresh token flow) or used, after the issuance of the initial refresh token. If absent, this interval is defined by refresh-token-ttl.

Using the refresh token flow, a client can obtain fresh access tokens and refresh tokens, until refresh-token-max-rolling-lifetime has elapsed since the first token request, as long as each refresh token is used before refresh-token-ttl seconds since its issuance.

Both these settings are configurable:

The default values configured for the non-templatized dynamic clients can be overriden during dynamic client registration or dynamic client management via two custom registration parameters:

  • refresh_token_ttl - defines the time to live of each individual refresh token.
  • refresh_token_max_rolling_lifetime - defines the time duration on which new refresh tokens can be obtained and used.

Tip

If a token with fewer scopes than the original access token is desired, the scope parameter can be used to tell the authorization server which scopes to include. Only scopes available in the original token are allowed to request.

Revoke

The revoke flow is used to revoke an access token or a refresh token.

The revoke flow is available on the oauth-revoke endpoint and is accessed with a POST and the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
token Yes None The token to revoke
token_type_hint No None Can be set to access_token or refresh_token
token_value_hint No None Can be set to id if the JTI of a JWT is sent instead of the actual JWT.
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used.

Introspect

The introspect flow is used to inspect a token, to see if it’s valid and to retrieve the associated data with that token.

The introspection flow is available on the oauth-introspect endpoint and is accessed with a POST and the content type application/x-www-form-urlencoded. The following request parameters are supported:

Attribute Required Default value Description
token Yes None The token to introspect
token_type_hint No None Can be set to access_token or refresh_token
token_value_hint No None Can be set to id if the JTI of a JWT is sent instead of the actual JWT. Note, this only works if the JWT is backed by a datastore.
client_id No None The client id of the requestor. If not set basic auth must be used
client_secret No None The secret of the client. If not set, basic auth must be used.

Introspect with application/jwt as accept header

The Curity Identity Server can also respond to requests in the introspection endpoint with the Accept: application/jwt header. When introspecting a valid access token, the Curity Identity Server responds with 200 OK and the JWT in the body of the response. An expired or invalid access token, causes the Curity Identity Server to respond with 204 No Content.

Json Web Key Set (JWKS)

The JSON Web Key Set endpoint publication of the currently active public keys. These can then be retrieved by the client to use when validating JWTs issued by this token server.

The JWKS is available on the oauth-anonymous endpoint and is unauthenticated. It expects the accept header application/json.

The oauth-anonymous endpoint can publish many services, and the JWKS service is located under <configured_path_of_anonymous>/jwks

Tip

If the oauth-anonymous endpoint is configured with path /oauth/v2/info then the JWKS service is published at /oauth/v2/info/jwks.

Device Authorization Flow

The device flow (Device Authorization Grant) is specified for internet connected devices that have a limited user interface, but need an Access Token or ID token. The device flow allows a device to offload the user interaction that is needed for user authentication and consent to a device of the user’s choice. The result of going through the Device Flow is still an Access Token and/or an ID token, making it possible for the device to operate as a fully enabled OAuth client.

The device flow is initiated by the device, that makes an authenticated back-channel request to the device authorization endpoint. In response to this request, Curity returns a device_code and a user_code to the device, together with a verification_uri that can be used by the user to verify the user_code. It is up to the device to instruct the user to visit the verification_uri.

The process of verifying the user_code is done in three steps:

  1. The user enters the user_code, giving Curity the opportunity to find the context that needs to be verified
  2. The user authenticates, using the device client’s settings
  3. The user is asked to confirm the access that device is requesting

While the user is verifying the user_code, the device can poll the token-endpoint to find out whether verification has completed. Once the user has confirmed access (step 3 above), the response of the device making a request to the oauth-token endpoint will be successful and include the requested token or tokens.

A more detailed description of how the device flow works in Curity can be found in Using the device flow.

Assertion Flow

The flow where the token endpoint can accept an assertion as authorization grant is referred to as the Assertion Flow. Using JWTs as assertions is specified in the JSON Web Token (JWT) Profile for OAuth, published as RFC7523.

To present a JWT as authorization grant, make a POST-request to the token endpoint that uses the value urn:ietf:params:oauth:grant-type:jwt-bearer for the grant_type-parameter, and provide the JWT through the assertion parameter.

A JWT used as assertion is commonly issued by the client that presents it. This is indicated by using the client id as value for the iss-claim of the JWT. In case a particular client must be able to present a JWT that was issued by another entity, the value to expect for the iss claim can be configured through that particular client’s settings.

If a JWT is presented as authorization grant, it needs to include a minimal set of claims, as specified in RFC7523:

Claim Description
iss identity of the entity that issued the JWT; defaults to the client_id value of the client that presents the JWT
sub name of the subject for which the token is requested
aud the receiver of the token, which should be the configured token endpoint in Curity
exp time until when the JWT may be used, in seconds since epoch. Curity will consider a configurable clock skew when this is being evaluated
jti unique identifier of the JWT token

When included in the JWT, Curity considers the nbf (not-before) and iat (issued-at) claims to control the time window in which the token is valid.

Token reuse

By default, Curity ensures that a token used as assertion grant can only be used once. This restriction can be overridden for individual clients by configuring the Assertion Grant settings of that particular client.

Logout Flow

When a client wants to indicate to the Token Service that a user is logged out, it can call the logout path on the Session endpoint (i.e. the end_session_endpoint in the Metadata). Doing so will log the user out of the associated Authentication Service, as well as notify all clients that the user has logged in to through their respective registered frontchannel- or backchannel logout uri’s, so called Single Logout.

Logout follows the OpenId Connect Session Management, OpenId Connect Backchannel Logout and OpenId Connect Frontchannel logout specifications.

More details are in Session Management and Logout.