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.
OAuth 2.0 Token Exchange¶
The OAuth 2.0 Token Exchange is a standardized token exchange flow for service to service impersonation, and AS to AS token conversion. It is specified in RFC 8693 and defines multiple ways to exchange tokens.
Token exchange is initiated by the Client making a call to the oauth-token
endpoint of the OAuth profile, using the grant_type urn:ietf:params:oauth:grant-type:token-exchange
.
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 | No | Unchanged | Indicates that new scopes, space separated, should be set on the requested token. |
audience | No | Unchanged | Indicates that new audiences should be set on the requested token, note that this parameter can be set multiple times for multi-value audience requests. |
grant_type | Yes | None | Must be set to urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | Yes | None | The token representing the party of whom the request is made. |
subject_token_type | Yes | None | A string defining the type of the subject_token. This should be a string from the RFC’s token type identifiers but can be customized when procedures or plugins are used. |
actor_token | No | None | The token representing the actor making the request. This token, when present, is assumed to be an access token issued by the Curity Identity Server, and must be introspectable by the server. |
actor_token_type | No* | None | Required when actor_token is present. The only acceptable
value is urn:ietf:params:oauth:token-type:access_token . |
requested_token_type | No | None | The expected token type of the token returned in the
access_token parameter.
If not set, the server or procedure will determine what
type should be returned. |
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 OAuth 2.0 Token Exchange grant in the Curity Identity Server is highly customizable, this is due to the inherent properties of the flow itself. It can be used for many purposes many of which are custom and use-case specific. The flow is therefore structured to be customized in token procedures or token procedure plugins. If no plugin or procedure is configured the default procedure will execute.
Default OAuth 2.0 Token Exchange Behaviour¶
The default procedure supports three different behaviours:
- Convert an opaque access token to an access token in JWT format
- Reduce the scopes (downscope) of an access token, returning a token with fewer scopes
- Reduce the audiences (downaudience) an access token, returning a token with fewer audiences
Functions 2 and 3 can be combined in a single request, both downscoping and downaudiencing the token.
1. Convert an opaque access token to an access token in JWT format
To convert an opaque token to a JWT access token (i.e. the phantom token flow) the following parameters should be sent to the token endpoint:
Attribute | Value |
---|---|
grant_type | urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | The original opaque access token issued by the same token profile in the Curity Identity Server. |
subject_token_type | urn:ietf:params:oauth:token-type:access_token |
requested_token_type | urn:ietf:params:oauth:token-type:jwt |
client_id | The client id of the requestor. If not set basic auth must be used |
client_secret | The secret of the client. If not set, basic auth or other auth methods must be used. |
No other parameters may be used.
2 or 3: Downscope or downaudience a token
This converts a token issued by the same token profile in the Curity Identity Server to a new access token with the same expiration, but with fewer scopes and/or audiences.
Attribute | Value |
---|---|
grant_type | urn:ietf:params:oauth:grant-type:token-exchange |
subject_token | The original opaque access token issued by the same token profile in the Curity Identity Server. |
subject_token_type | urn:ietf:params:oauth:token-type:access_token |
requested_token_type | urn:ietf:params:oauth:token-type:access_token |
scope | If set, a space separated string of the new scopes requested. These must
be a subset of the scopes in the original subject_token . |
audience | May be set multiple times if multiple audiences are requested. If set, these must
be a subset of the audience in the original subject_token . |
client_id | The client id of the requestor. If not set basic auth must be used |
client_secret | The secret of the client. If not set, basic auth or other auth methods must be used. |
No other parameters may be used.
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 todisabled
, 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 byrefresh-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:
- For each configuration-backed client.
- On the non-templatized dynamic clients configuration settings.
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:
- The user enters the
user_code
, giving Curity the opportunity to find the context that needs to be verified- The user authenticates, using the device client’s settings
- 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.