The process of authorizing a token request lets the user authenticate its identity that is bound to the delegation on which the issued token is based. On top of user authentication, it is also possible to actively involve the user in agreeing with the permissions that the client or App requested for that delegation. The process in which a user is presented with a choice to (selectively) grant access for certain permissions to a client, is referred to as the gathering of user consent.
Curity supports user consent based on requested claims or scopes. Scopes are either expanded to claims (e.g. in case of an OpenId Connect scope like profile, email, etc.) or projected on to claims directly. Once user consent is enabled, when a client starts a flow that involves user interaction (i.e. code, implicit, assisted token or device authorization flow), the authenticated user will be asked to confirm that the requested claims are OK to be bound to the delegation. This will result in tokens being issued with claims and scopes that the user confirmed.
profile
email
With user consent enabled, a client client-one redirects the user to Curity authorize a token request for scopes read, openid and email with the following URL:
client-one
read
openid
https://curity.example.com/authorize?client_id=client-one&response_type=code&scope=read%20openid%20email&state=1512320823&redirect_uri=https://client-one.example.com
After the user authenticates as teddie, the following screen will be shown in the user’s browser:
teddie
The user is involved in confirming the requested claims when user consent is enabled for a client. The purpose of asking for user consent, is to involve the user into giving its permission for the requested claims and/or scopes. Once this permission is given, it is established and valid for as long as the delegation that the user consent was bound to. This means that, when a delegation exists for a user that has authenticated for a new request to authorize a token, the claims that were bound to the existing delegation are used to check if they satisfy the new authorization request. In case the new request asks for the same or less permissions than the existing delegation provided, then the user will not be asked to confirm the request, i.e. the currently active delegation’s permissions are still valid and used as such.
If you want to assert that the user is always asked for consent with an authorization request, you can include the prompt=consent parameter in the authorization request (as specified in OpenID Connect).
prompt=consent
If the configuration does not allow the claims to be deselected, but they should be for a certain transaction, then prompt=consent_allow_deselection can be provided to enable deselection of certain claims only for that request. If this is used, the prompt value may or may not include consent as well. If consent is not included and the client isn’t configured to require consent, the user will not be prompted (and consequently consent_allow_deselection will have no effect). If consent is enabled on the client, deselection of the claims will be allowed (irrespective of the configured value for deselection). If both consent and consent_allow_deselection are provided, then they should be separated on the query string by a space (that is properly URL encoded).
prompt=consent_allow_deselection
consent
consent_allow_deselection
Below is a transcript that shows an example of how an existing delegation can influence how user consent is being gathered.
A client requests user authorization for a token, asking for scopes read, openid and phone The scopes read, openid and phone are translated into read, sub, and phone and phone_verified claims The user authenticates, and is asked to give its consent to the read, sub, phone and phone_verified claims A delegation is created that binds it with the read, sub, phone and phone_verified claims, and A token is issued, based on that delegation, with the read, sub, phone and phone_verified claims, which translate to the read, openid and phone
phone
sub
phone_verified
Next, the client asks the user to authorize a new token request with a subset of the scopes of the previous request. This happens before the delegation of the previous token has expired:
The client requests user authorization for a token, asking for scope read The scope read is translated into the claim read The user authenticates The active delegations of the user indicate that current permissions exist for claims read, sub, phone and phone_verified, therefore no new user consent is required to satisfy the request for claim read A delegation is created that binds it with the read claim, and the token is issued based on that delegation
prompt
When a client requests authorization for an Access Token, and it wants the user to consent to the requested scopes, it can include prompt=consent in the request parameters and redirect the user to:
https://curity.example.com/authorize?client_id=client-one&response_type=code&scope=read%20openid%20email&state=1512320823&redirect_uri=https://client-one.example.com&prompt=consent
Note
The client does not need to be configered with User Consent enabled, as including prompt=consent in the parameters will also trigger user consent gathering for that request.
When the user is allowed to deselect requested claims during user consent gathering, the client can be configured with Allow Deselection enabled, or it can include the consent_allow_deselection value in the prompt parameter. The URL to redirect the user to will be like this:
Allow Deselection
https://curity.example.com/authorize?client_id=client-one&response_type=code&scope=read%20openid%20email&state=1512320823&redirect_uri=https://client-one.example.com&prompt=consent+consent_allow_deselection
The client does not need to be configered with Allow Deselection enabled, as including prompt=consent_allow_deselection in the parameters will also trigger consent deselection for that request.
User interactive consent can be enabled per client. It is only available when the client supports user interactive flows. To enable it, toggle the slider.
The user interface uses the oauth/consent.vm template to render consent. This template includes the use of the client logo, privacy policy and terms of services URL’s if they are configured. Internationalized messages for the user consent template can be managed in the oauth/messages file, where the translation of the requested claims can also be stored.
oauth/consent.vm
oauth/messages
The file usr/share/messages/core/en/views/oauth/messages describes the following translations for the sub claim:
usr/share/messages/core/en/views/oauth/messages
consent.claim-names.sub=User ID consent.claim-descriptions.sub=Your user account ID
You can override these default translations by creating a file usr/share/messages/overrides/en/views/oauth/messages where you can redefine the consent.claim-names.sub claim name and the consent.claim-descriptions.sub description.
usr/share/messages/overrides/en/views/oauth/messages
consent.claim-names.sub
consent.claim-descriptions.sub
Tip
To enforce a particular locale, a client can include the ui_locales parameter in the request, see the paragraph About Locales to learn more about localization
ui_locales
By default, prefix scopes are shown in the User Consent Page. page as any other scope that does not map to a known claim.
The description shown in the User Consent Page is the one that was configured for the scope.
The claim will be shown as the requested value, unless a localized message for the prefix is defined, as we’ll see.
For example, if you have a prefix scope called ttid: (for transaction id) with a configured description Rådande Transaktion, and a client requests the ttid:SN1234567890 scope, the default User Consent screen would appear as shown below:
ttid:
Rådande Transaktion
ttid:SN1234567890
The description of the scope, in this case, is shown as it is in the scope’s configuration for any Locale.
If you need to localize the description of the scope, you should set the description of the scope to a message key rather than an actual message.
Keeping with the current example, a good message key could be scopes.description.ttid.
scopes.description.ttid
The claim itself can also be localized, but for prefix scopes, the message key needs to have the same value as the prefix scope, ttid: in this case.
In summary, supposing you configured a prefix scope called ttid: and set its description to scopes.description.ttid, then you would have to create a message file with values for these keys on each Locale you want to support, as explained in About Locales:
usr/share/messages/overrides/en/messages.properties
ttid=Transaction: scopes.description.ttid=Approve the current transaction
Notice how certain characters, such as the : character above, must be escaped in properties files.
:
properties
The following image shows what the default template would look after the above messages were defined for the English locale, for a client requesting, among other claims, the ttid:ABC123456 scope:
ttid:ABC123456
If you would like to override the default template, templates/overrides/views/oauth/consent.vm, you can simply create a file at templates/overrides/views/oauth/consent.vm and modify it as appropriate.
templates/overrides/views/oauth/consent.vm
Currently, the default consent page iterates over the consent entries as follows:
templates/core/views/oauth/consent.vm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#foreach ($entry in $_consentEntries.entrySet()) <li> #set ( $keyName = $entry.key ) #set ( $parameterName = "consent.$keyName") #if ($entry.value.scopePrefix != "") #define($prefixName)#message("$entry.value.scopePrefix")#end #set ( $suffix = $entry.value.scopeSuffix ) #set ( $claimLabel = "$prefixName$suffix" ) #else #define($claimLabel)#message("$entry.value.displayName")#end #end <label class="block full-width relative" #if ($entry.value.required == "true") ><input type="checkbox" name="$parameterName" id="$parameterName" checked disabled> <label class="consent-entries-list-checkbox"></label> <input type="hidden" name="$parameterName" #else ><input type="checkbox" name="$parameterName" id="$parameterName" checked #end > <label class="consent-entries-list-checkbox"></label> <span class="consent-entries-list-name">$claimLabel</span> ...
The highlighted lines show how the entry’s name is selected depending on whether or not the entry represents a prefix scope, setting an appropriate value for the claimLabel variable for each case.
claimLabel
Curity also supports extending the authorization request with consentors, which are an extensibility mechanism used to perform additional processing, including validation, information retrieval, and user interaction. Consentors are run during the authorization request of the code and implicit grants, and on the assisted token request, after user-consent has been collected.
See the consentors documentation for additional information.