Table of Contents
You can use OpenID Connect’s “Hybrid” flows to issue two access tokens for a client through a single authorization flow.
This article describes a use case of issuing access tokens with restricted scopes and/or a shortened duration, and how Authlete processes it.
The hybrid flows are useful for authorization server to issue access tokens for a client that consists of a native application (e.g. mobile app) and an web server application (e.g. app backend), with a single authorization request.
A native application is often a public client, whose security risk is higher than a confidential client such as an web server application. In order to mitigate the risk, the hybrid flows can issue an access token for each side and restrict scopes (subsetting) of the particular token for the native application.
Furthermore, for an web server application that makes requests to high-stakes APIs, the flows allow authorization servers to issue access tokens with a shortened duration.
Authlete supports the hybrid flows. For example, its /auth/authorization/issue API can handle an authorization request with “response_type=code token” and create an authorization response including an authorization code and an access token. Also, its /auth/token API accepts a token request including the authorization code and creates a token response including another access token.
Authlete’s token updating API (/auth/token/update API) allows authorization servers to modify properties of access tokens, such as scopes, duration. These modifications are applied to access tokens stored in Authlete.
On receiving such access tokens from clients, resource servers will check status and details of the tokens, using Authlete’s introspection API (/auth/introspection
) and obtain the information modified in the previous step.
This section describes examples where an authorization server issues two access tokens on receiving an authorization request with “response_type=code token” and modifies scopes and duration for each of the tokens.
On receiving an authorization request from a client (via a user agent), an authorization server typically does the following processes.
The following example is a response from /auth/authorization/issue API (step #7). It contains an access token as a value of “accessToken”, to be provided from the authorization server’s authorization endpoint to the client. Content of “responseContent” indicates that the token has scope=openid profile payment. (all examples below are folded for readability)
{
"type": "authorizationIssueResponse",
"resultCode": "A040001",
"resultMessage": "[A040001] The authorization request was processed successfully.",
"accessToken": "stm3IfTHV_F1iVKEYQBJA58XMzA7OQ59-MQpdM3NH6c",
"accessTokenDuration": 1800,
"accessTokenExpiresAt": 1596379999493,
"action": "LOCATION",
"authorizationCode": "iEATjO9V24Rubj1_PnATziCGh4ivVPRcTK_VZOsGplI",
"responseContent": "https://client.example.org/cb/example.com
#code=iEATjO9V24Rubj1_PnATziCGh4ivVPRcTK_VZOsGplI
&access_token=stm3IfTHV_F1iVKEYQBJA58XMzA7OQ59-MQpdM3NH6c
&token_type=Bearer
&expires_in=1800
&scope=openid+profile+payment"
}
The access token has three scopes: openid, profile and payment. The authorization server modifies the granted scopes (removes unnecessary scopes) using Authlete’s /auth/token/update API (step #6, #7). In this example, the server removes “payment” scope and preserves “openid” and “profile.”
If JWT-based access token is enabled, the value to be specified as “accessToken” is a value of “accessToken” in the previous response, which is not a JWT-formatted one (“jwtAccessToken”).
curl -s -X POST $apiUrl/auth/token/update \
-u $apiKey:$apiSecret \
-H 'Content-type: application/json' \
-d '{"accessToken":"stm3IfTHV_F1iVKEYQBJA58XMzA7OQ59-MQpdM3NH6c", \
"scopes":["openid","profile"]}'
{
"type": "tokenUpdateResponse",
"resultCode": "A135001",
"resultMessage": "[A135001] Updated the access token successfully.",
"accessToken": "stm3IfTHV_F1iVKEYQBJA58XMzA7OQ59-MQpdM3NH6c",
"accessTokenExpiresAt": 1596379999000,
"action": "OK",
"scopes": [
"openid",
"profile"
],
"tokenType": "Bearer"
}
The authorization server will send back the content of “responseContent”, obtained from a response of /auth/authorization/issue API as shown above, to the client (step #8).
Note that values of scope parameter in the “responseContent” are the same as the original ones (“scope=openid+profile+payment”). Also note that, if JWT-based access token is enabled, the values of “scopes” in the access token are not updated i.e. “scope”: “openid profile payment”.
On receiving a token request from a client (step #13), an authorization server typically does the following process.
The following example is a response from /auth/token API (step #15). It contains an access token as a value of “accessToken”, to be provided from the authorization server’s token endpoint to the client. A value of “accessTokenExpiresAt” indicates that the token is to be expired on 1596380052227 (in Unix time).
{
"type": "tokenResponse",
"resultCode": "A050001",
"resultMessage": "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
"accessToken": "zcxCRPL3P1n7gUnn1gnRAz3nndUdYeyilpU7txGE3gg",
"accessTokenDuration": 1800,
"accessTokenExpiresAt": 1596380052227,
"action": "OK",
"clientId": 17201083166161,
"clientIdAlias": "clientapp01",
"clientIdAliasUsed": false,
"grantType": "AUTHORIZATION_CODE",
"idToken": "eyJhbGciOiJIUzI1NiJ9. eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjE3MjAxMDgzMTY2MTYxIl0s ImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTk2NDY0NjUy LCJpYXQiOjE1OTYzNzgyNTJ9. uJiJxISW7d0HEgOyQsIFbqptOREeqs9zJYMs_ZhZ72w",
"refreshToken": "98YoC89H9CYcc56amo0bvNZ8pV02dYZmxCvB0Wz31jU",
"refreshTokenDuration": 9000,
"refreshTokenExpiresAt": 1596387252227,
"responseContent":
"{\"access_token\":\"zcxCRPL3P1n7gUnn1gnRAz3nndUdYeyilpU7txGE3gg\",
\"refresh_token\":\"98YoC89H9CYcc56amo0bvNZ8pV02dYZmxCvB0Wz31jU\",
\"scope\":\"openid profile payment\",
\"id_token\":
\"eyJhbGciOiJIUzI1NiJ9.
eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjE3MjAxMDgzMTY2MTYxIl0s
ImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTk2NDY0NjUy
LCJpYXQiOjE1OTYzNzgyNTJ9.
uJiJxISW7d0HEgOyQsIFbqptOREeqs9zJYMs_ZhZ72w\",
\"token_type\":\"Bearer\",
\"expires_in\":1800}",
"scopes": [
"openid",
"profile",
"payment"
],
"subject": "testuser01"
}
In the same way as the previous example, the authorization server modifies the duration of the access token using Authlete’s /auth/token/update API (step #16, #17). In this example, it specifies 1596379152000, that means 900 seconds (900,000 milliseconds) shorter than the original duration.
curl -s -X POST $apiUrl/auth/token/update \
-u $apiKey:$apiSecret \
-H 'Content-type: application/json' \
-d '{"accessToken":"zcxCRPL3P1n7gUnn1gnRAz3nndUdYeyilpU7txGE3gg", \
"accessTokenExpiresAt":1596379152000}'
{
"type": "tokenUpdateResponse",
"resultCode": "A135001",
"resultMessage": "[A135001] Updated the access token successfully.",
"accessToken": "zcxCRPL3P1n7gUnn1gnRAz3nndUdYeyilpU7txGE3gg",
"accessTokenExpiresAt": 1596379152000,
"action": "OK",
"scopes": [
"openid",
"profile",
"payment"
],
"tokenType": "Bearer"
}