UMA grant flow
The UMA grant flow issues an RPT to the requesting party to allow access to a resource.
The implementation in AM covers the following scenarios:
-
The requesting party wants to perform an action over a resource (for example, downloading it), and the resource owner has already granted them that permission.
During the UMA grant flow, AM issues the requesting party an RPT that they can present to the resource server to access the resource.
-
The requesting party wants to perform an action over a resource (for example, downloading it), and the resource owner has not granted them that permission.
During the UMA grant flow, AM denies access to the resource, and sends the resource owner a request for permission on behalf of the requesting party.
If the resource owner grants their permission (which happens asynchronously), the requesting party requests a new permission ticket and applies for another RPT.
This diagram shows the first scenario:
Grant flow explained
-
A requesting party, using a client application, requests access to an UMA-protected resource (labeled 1 and 2 in the diagram above).
-
The resource server checks the existing token (3) and determines that the requesting party does not have the correct privileges to access the resource. The resource server returns a permission ticket (4) to the client.
-
The client uses the permission ticket and a claim token to send an RPT from AM (5) and (6).
-
AM makes a policy decision using the requested scopes, the scopes permitted in the registered resource, and the user-created policy, and if successful returns an RPT (7 and 8).
-
The client presents the RPT to the resource server (9), which must verify the token is valid using the AM introspection endpoint (10). If the RPT is confirmed to be valid and not expired (10), the resource server can return the protected resource to the client for access by the requesting party (11).
Perform the steps in the following procedures to issue an RPT to a requesting party, and have it rejected as in the second scenario. The resource owner will then grant permission to the resource, and the requesting party will attempt the flow again:
Acquire a PAT on behalf of a resource owner
This example assumes that a confidential client called UMA-Resource-Server is registered in AM with, at least, the following configuration:
-
Client Secret:
password
-
Scopes:
uma_protection
-
Grant Types:
Resource Owner Password Credentials
The example uses the Resource Owner Password Credentials grant, but you can use any grant type to obtain the PAT,
except the Client Credentials grant. The example also assumes that an identity for the resource owner,alice
, exists
in AM.
-
Send a POST request to the OAuth 2.0
access_token
endpoint.This example uses the
Resource Owner Password Credentials
grant:$ curl \ --request POST \ --data 'grant_type=password' \ --data 'scope=uma_protection' \ --data 'username=alice' \ --data 'password=Ch4ng31t' \ --data 'client_id=UMA-Resource-Server' \ --data 'client_secret=password' \ "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token" { "access_token": "oMsRVDXHYsWAC0KClr6dmX2_cIc", "scope": "uma_protection", "token_type": "Bearer", "expires_in": 3599 }
-
The value returned in
access_token
is the Protection API Token, or PAT Bearer token.
To use the |
Create a permission ticket
When the resource server receives a request for access to a resource, it contacts the authorization server to acquire a permission ticket. The permission ticket associates a request for a particular resource with the corresponding scopes. The resource owner’s PAT bearer token is used to map the request to the correct identity.
The permission ticket and the claim token are used to obtain an RPT. A new permission ticket must be used for each attempt to acquire an RPT.
This example assumes that a confidential client called UmaClient is registered in AM with, at least, the following configuration:
-
Client Secret:
password
-
Scopes:
openid
,download
-
Grant Types:
Resource Owner Password Credentials
,UMA
This example uses the Resource Owner Password Credentials grant, but you can use any grant type, except the Client Credentials one.
-
Token Endpoint Authentication Method:
client secret post
Confidential OpenID Connect clients can use several methods to authenticate, but this example uses
client secret post
for clarity. For more information, see OIDC client authentication.
The example also assumes that an identity for the resource owner, bob
, exists in AM.
-
Send a POST request to the UMA
permission_request
endpoint:$ curl \ --request POST \ --header 'authorization: Bearer 057ad16f-7dba-4049-9f34-e609d230d43a' \ (1) --header 'cache-control: no-cache' \ --header 'content-type: application/json' \ --data '[ { "resource_id" : "ef4d750e-3831-483b-b395-c6f059b5e15d0", (2) "resource_scopes" : ["download"] } ]' \ https://openam.example.com:8443/openam/uma/realms/root/permission_request { "ticket": "eyJ0eXAiOiJ…XPeJi3E" (3) }
1 Use the PAT Bearer Token previously acquired on behalf of the resource owner. 2 Specify ID of the registered resource for which this permission ticket will maintain permission state information. See Register an UMA resource (REST). 3 The value returned in the ticket
property is the permission ticket, which is used to obtain an RPT. See Obtain an RPT.The default lifetime for an UMA permission ticket is 120 seconds. Attempting to obtain a requesting party token after the permission ticket has expired will fail with the following error message:
{ "error_description": "The provided access grant is invalid, expired, or revoked.", "error": "invalid_grant" }
To alter the default lifetime of a permission ticket, go to Realms > Realm Name > Services > UMA Provider, and edit the Permission Ticket Lifetime (seconds) property.
Gather claims
The UMA specification lets a requesting party (Bob, in our example) identify themselves in multiple ways during an UMA grant flow. This process of identification is also called claims gathering.
The authorization server must gather claims from the requesting party to create a claim token.
-
Send a POST request to the OAuth 2.0
access_token
endpoint.The value returned in the
id_token
property is the claim token required to obtain an RPT, along with the permission ticket acquired earlier:$ curl \ --request POST \ --data 'client_id=UmaClient' \ --data 'client_secret=password' \ --data 'grant_type=password' \ --data 'scope=openid' \ --data 'username=bob' \ --data 'password=Ch4ng31t' \ https://openam.example.com:8443/openam/oauth2/realms/root/access_token { "access_token": "f09f55e5-5e9c-48fe-aeaa-d377de88e8e6", "refresh_token": "ee2d35f6-5819-4734-8b3e-9af77a545563", "scope": "openid", "id_token": "eyJ0eXA...FBznEB5A", (1) "token_type": "Bearer", "expires_in": 4999 }
1 The value returned in the id_token
property is the claim token, which is used to obtain an RPT. See Obtain an RPT.
To use the |
Obtain an RPT
The requesting party makes a request using the permission ticket and the claim token, in exchange for an RPT.
-
Send a POST request to the OAuth 2.0
access_token
endpoint.You must include the permission ticket,
ticket
, and theclaim_token
.The following example results in an error description, indicating that "The client is not authorised to access the requested resource set." The authorization server then sends a request to the resource owner to allow or deny access to the requesting party.
$ curl \ --request POST \ --data 'client_id=UmaClient' \ --data 'client_secret=password' \ --data 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \ --data 'ticket=eyJ0eXAiOiJ...XPeJi3E' \ (1) --data 'claim_token=eyJ0eXA...FBznEB5A' \ (2) --data 'claim_token_format=http://openid.net/specs/openid-connect-core-1_0.html#IDToken' \ https://openam.example.com:8443/openam/oauth2/realms/root/access_token { "ticket": "eyJ0eXAiOiJ...XPeJi3E", "error_description": "The client is not authorised to access the requested resource set. A request has been submitted to the resource owner requesting access to the resource", "error": "request_submitted" }
1 Specify the permission ticket acquired earlier. See Create a permission ticket. 2 Specify the claim token acquired earlier. See Gather claims. The default lifetime for an UMA permission ticket is 120 seconds. Attempting to obtain a requesting party token after the permission ticket has expired will fail with an error message as follows:
{ "error_description": "The provided access grant is invalid, expired, or revoked.", "error": "invalid_grant" }
If the ticket has expired, obtain another by repeating the steps in Create a permission ticket.
To change the default lifetime of a permission ticket, go to Realms > Realm Name > Services > UMA Provider, and edit Permission Ticket Lifetime (seconds).
-
The resource owner, Alice, logs into AM to view the access request.
Alice clicks Shares > Requests, and clicks Allow to grant download access to Bob, the requesting party.
Figure 1. Consent Screen Presented to the Resource Owner -
Because each permission token can only be used once, request a new permission token by performing the steps in Create a permission ticket.
-
Resubmit the previous POST request for the RPT, with the new permission ticket obtained in the previous step and the original claim token:
$ curl \ --request POST \ --data 'client_id=UmaClient' \ --data 'client_secret=password' \ --data 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \ --data 'ticket=eyJ0efBiOiJ...XPeJc2A' \ (1) --data 'claim_token=eyJ0eXA...FBznEB5A' \ (2) --data 'claim_token_format=http://openid.net/specs/openid-connect-core-1_0.html#IDToken' \ https://openam.example.com:8443/openam/oauth2/realms/root/access_token { "access_token": "Aw4a92ZoKsjadWKw2d4Rmcjv7DM", "token_type": "Bearer", "expires_in": 3599 }
1 Specify a refreshed permission ticket acquired earlier, otherwise you will receive a response such as: The provided access grant is invalid, expired, or revoked
. See Create a permission ticket.2 Specify the same claim token as the first request for an RPT. The
access_token
is the RPT, which lets the requesting party access the resource through a client. -
You can use the
/oauth2/introspect
endpoint to inspect the properties of the RPT.Use the PAT issued to the resource owner for authenticating to the authorization server, and specify the RPT token in a query parameter named
token
, as follows:$ curl \ --header 'authorization: Bearer 057ad16f-7dba-4049-9f34-e609d230d43a' \ "https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/introspect?token=Aw4a92ZoKsjadWKw2d4Rmcjv7DM" { "active": true, "permissions": [ { "resource_id": "ef4d750e-3831-483b-b395-c6f059b5e15d0", "resource_scopes": [ "download" ], "exp": 1522334692 } ], "token_type": "access_token", "exp": 1522334692, "iss": "https://openam.example.com:8443/openam/oauth2" }
Gather claims interactively
When claims are gathered with no user interaction, AM accepts an id_token
as the
provided claim_token
. The identity of the requesting party is the subject of the id_token
.
AM 7.2.0 also supports interactive claims gathering. In this case, AM redirects the client to a
claims_gathering
endpoint, to request additional claims. The claims gathering endpoint also offers the requesting party
the option of a PCT, which persists claims across
authorization processes. If the client wants to request another RPT later, they can simply send the PCT, along with the access token request. The authorization server
can opt to re-use the claims from the PCT (provided they have not expired) instead of forcing the user through yet
another interactive claims gathering flow.
The claims gathering process can be initiated two ways:
-
The client sends an access token request without providing a
claim_token
. AM returns aneed_info
error, and aredirect_user
hint. The client then constructs a claims gathering request, using the hint, and displays that page to the end user. -
The client locates the URL of the claims gathering endpoint in the UMA discovery metadata (
/uma/.well-known/uma2-configuration
) and initiates the claims gathering flow without first going to the token endpoint.
The interactive claims gathering process can take longer than the lifetime of the permission ticket. You should adjust the permission ticket lifetime so that end users are able to authenticate during that lifetime. |
This diagram shows an interactive claims gathering scenario:
Interactive claims gathering grant flow
-
A requesting party, using a client application, requests access to an UMA-protected resource (labeled 1 and 2 in the diagram above).
-
The resource server checks the existing token (3) and determines that the requesting party does not have the privileges to access the resource. The resource server returns a 401 Unauthorized response, along with a permission ticket (4) to the client.
-
The client uses the permission ticket and a claim token to send an RPT to AM (5).
-
AM determines that additional claims are required and returns a 403 response, with the rotated permission ticket and a redirect to the claims gathering endpoint (6).
-
The client redirects the user to the claims gathering endpoint (7 and 8]).
-
AM determines that the user is not yet authenticated, and redirects the user to the claims gathering tree (9).
-
The user authenticates and is redirected back to the claims gathering endpoint (10, 11, 12).
-
The user provides the additional claims and is redirected to the claims redirect URI, with the updated permission ticket (13 and 14).
-
The client requests an RPT, using the updated permission ticket (15).
-
AM makes a policy decision using the requested scopes, the scopes permitted in the registered resource, and the user-created policy. If successful, AM returns an RPT and, optionally, a PCT (16).
-
The client presents the RPT to the resource server (17), which must verify the token is valid using the AM introspection endpoint (18). If the RPT is confirmed to be valid and non-expired, the resource server returns the protected resource to the client for access by the requesting party (19).
Enable interactive claims gathering
Interactive claims gathering is disabled by default.
To enable interactive claims gathering across all realms, go to Configure > Global Services > UMA Provider > Claims Gathering and set Interactive Claims Gathering Enabled.
To enable interactive claims gathering for a specific realm, go to Realms > Realm Name > Services > UMA Provider > Claims Gathering and set Interactive Claims Gathering Enabled.
For details of the other configuration options on this tab, see Claims gathering.
When interactive claims gathering is enabled:
-
the
claims_gathering
endpoint is accessible -
the UMA grant type handler returns a
redirect_user
error, redirecting the user to theclaims_gathering
endpoint -
the UMA provider validates PCTs
-
the UMA provider does not consult the
claim_token
parameter to gather claims non-interactively
Protect permission tickets with PKCE
When claims are gathered interactively, the permission ticket can hold sensitive information about the requesting party. You should therefore protect permission tickets obtained in an interactive claims gathering flow, in the same way you would protect other sensitive resources.
You can protect permission tickets with PKCE, in a similar flow to the
Authorization code grant with PKCE flow. In this case, the code_challenge
and
code_challenge_method
are submitted with the permission ticket, in the request to the claims_gathering
endpoint.
For example:
$ curl --request GET \
--Cookie "iPlanetDirectoryPro=AQIC5wM…TU3OQ*" \
--data "claims_redirect_uri=https://www.example.com:443/callback" \
--data "ticket=eyJ0eXA…jpY" \
--data "client_id=UmaClient" \
--data "csrf=AQIC5wM…TU3OQ*" \
--data "state=abc123" \
--data "code_challenge=j3wKnK2Fa_mc2tgdqa6GtUfCYjdWSA5S23JKTTtPF8Y" \
--data "code_challenge_method=S256" \
"https://openam.example.com:8443/openam/uma/realms/root/realms/alpha/claims_gathering"
To specify that clients must include PKCE challenges in their requests, go to Services > OAuth2 Provider >
Advanced, and set the Code Verifier Parameter Required
property, either for the specific realm, or as a global service
parameter. Note that the UMA provider inherits this setting from the OAuth 2.0 provider. As such, it affects all OAuth 2.0
flows, and not just UMA flows.
Protect PCTs with certificate-bound proof-of-possession
Persisted claims tokens (PCTs) let clients obtain an RPT without having to go through the interactive claims gathering process multiple times. They are similar to OAuth 2.0 refresh tokens and, as such, should be protected.
Proof-of-possession (PoP) lets you ensure that the client to whom the PCT was issued is the client that subsequently attempts to use it.
In UMA flows, AM supports certificate-bound proof-of-possession only. JWK-based proof-of-possession is not supported. |
You can protect PCTs with PoP in a similar flow to the OAuth 2.0 certificate-bound proof-of-possession flow.
The confirmation key (cnf_key
) is sent alongside the request for the RPT, for example:
$ curl \
--request POST \
--header "content-type: application/json" \
--data "client_id=UmaClient" \
--data "client_secret=password" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "ticket=eyJ0eXA…jpY" \
--data "cnf_key=eyJ4NXQ…==" \
"https://openam.example.com:8443/openam/oauth2/realms/root/realms/alpha/access_token" \
{
"access_token": "HexwGYRSK4Dy1yI_aFXirdFT1-I",
"pct": "eyJ0eXA…jpY",
"token_type": "Bearer",
"expires_in": 3599
}