Configuring OAuth 2.0 Rich Authorization Requests (RAR) and OpenID for Verifiable Credential Issuance
OAuth 2.0 Rich Authorization Requests
OAuth 2.0 Rich Authorization Requests RAR is an extension of the OAuth 2.0 framework. It enables clients to request additional information or attributes about a user or resource during authorization. This additional information allows the authorization server to make more informed decisions, enabling fine-grained access control.
In the OAuth 2.0 framework, a client typically requests permission to access a user’s resources on their behalf. With RAR, the client can also request additional details about the user or resource, such as location, device type, or group membership. The authorization server can then use this information to make more informed authorization decisions.
RAR is a prerequisite for Verifiable Credential Issuance, which is discussed in the following section.
Configuring provider.yml
- The definition configuration defines new set of configuration parameters called
authorization_details_types_supported
,authorization_details_types_schema
,ignore_unknown_authorization_details_type
. - authorization_details_types_supported indicates the supported types of authorization details. This parameter also defines the strategy for computing the identifier for each incoming authorization_details.
default - A hash of specific fields in the JSON payload.
sha512 - A SHA 512 hash of the entire payload.
custom - Requires an inline JavaScript function that is provided in the script field. - authorization_details_types_schema is an array of authorization_details_types. This parameter references a JSON schema file which is used to validate incoming authorization_details.
# Copyright contributors to the IBM Verify Identity Access OIDC Provider Resources project
version: 24.12
logging:
level: debug
definition:
id: 1
name: OIDC Definition
grant_types:
- authorization_code
- password
- client_credentials
- implicit
- refresh_token
- urn:ietf:params:oauth:grant-type:token-exchange
authorization_details_types_supported:
- type: payment_initiation
strategy: default
- type: account_information
strategy: sha512
- type: openid_credential
strategy: custom
script: |
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.OAuthMappingExtUtils);
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.SignHelper);
var ads = stsuu.getContextAttributes().getAttributeValueByName("authorization_details");
StringSigningHelper.calculateHash("testuser123","SHA512")
ignore_unknown_authorization_details_type: false
authorization_details_types_schema:
- type: payment_initiation
content: '@schema/payment_initiation.json'
- type: account_information
content: '@schema/account_information.json'
- type: openid_credential
content: '@schema/openid_credential.json'
pre_mappingrule_id: isvaop_pretoken # Pre-Token mapping rule ID.
post_mappingrule_id: isvaop_posttoken
base_url: https://isvaop.ibm.com:445/isvaop
token_settings: # Token Settings
issuer: https://isvaop.ibm.com # OP's issuer URI.
signing_alg: PS256 # Signing algorithm for ID token generated.
signing_keystore: isvaop_signing # Signing keystore name.
signing_keylabel: jwtsigning # Signing key label.
attribute_map: # Attribute mapping to resolve claims. also refer to attributesources.yml
surname: surname
server:
ssl:
key: ks:isvaop_keys/httpserverkey
certificate: ks:isvaop_keys/httpservercert
jwks:
signing_keystore: isvaop_signing
secrets:
obf_key: "ENC:iUt+3MzCntxSL2FPTUuJqER79UaiRSApMz3cbgJm4yzuiv6H7KN8ADsamX6+Qre1oTsATjnb1bJ0Lmi7WWfxWeGT477yqqvgVayFlCDIFzZeNkdINjASfTE3B+/3Sm9YjIYuWtZdySiXeydhJXSiOGU9osdA9g2BZXR4eMrXNutCuaSvFH6MY+TyOH5q15vy6vEWOebJQHrnug0A8rN6NF8G8XaxCe/+yqH57jJpdhm0N7iUydIYOBOQ1wDgCc8nRMWkQqlkcRhDZvLLAIlhoshYvo06ubyryt8/vv/0AvTLq9AIiQoL8CtYLr+SNZlzWe4CnHYZdO9S+AIrUOVORw=="
enc_key: "@keys/private.pem"
Configuring the static client
authorization_details_types
indicates the list of supported types specific to a client.
# Copyright contributors to the IBM Verify Identity Access OIDC Provider Resources project
clients:
- client_id: clientRAR
client_secret: "OBF:U2FsdGVkX19iBhlwc53QkybjO6RjFHhSbz4VRudYHA=" # Client secret that is used for client authentication and/or JWT signing/encryption. `OBF:` indicates obfuscated string.
client_name: clientRAR # Name of the client.
client_id_issued_at: 1642399207 # Timestamp (in seconds) from when the client is created.
enabled: true # Set to `true` to enable this client
grant_types: # Grant type that the client is allowed to use at the token endpoint.
- authorization_code
- password
- client_credentials
- implicit
- refresh_token
- urn:openid:params:grant-type:ciba
- urn:ietf:params:oauth:grant-type:token-exchange
response_types: # Response type that the client is allowed to use at the authorization endpoint.
- code id_token
- code
- code token
- none
- code token id_token
redirect_uris: # Redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows.
- https://www.rp.com/redirect
request_uris: # Request URIs that are pre-registered by the Relying Party for use at the OIDC Provider.
- https://www.rp.com/request/test.jwt
scopes: # A list of scope values that the client can use when requesting access tokens.
- cdr:registration
- openid
- profile
jwks_uri: https://www.rp.com/oidc/endpoint/default/jwks
id_token_signed_response_alg: PS512
token_endpoint_auth_method: client_secret_post
token_exchange_settings:
client_groups:
- benefits
- insurance
supported_subject_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
supported_actor_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
supported_requested_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
authorization_details_types:
- payment_initiation
- account_information
- openid_credential
Dynamic client request
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/register' \
--header 'Content-Type: application/json' \
--data '{
"redirect_uris": [
"https://www.google.com"
],
"grant_types": [
"authorization_code",
"client_credentials"
],
"response_types": [
"code"
],
"authorization_details_types":["account_information","openid_credential"],
"token_endpoint_auth_method": "client_secret_post"
}'
Authorization code request with RAR
curl --location ' https://isvaop.ibm.com:445/isvaop/oauth2/authorize' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=clientRAR' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'scope=test' \
--data-urlencode 'redirect_uri=https://www.google.com' \
--data-urlencode 'response_type=code' \
--data-urlencode 'authorization_details=[{
"actions": null,
"type": "account_information",
"locations": [
"https://example.com/payments"
],
"identifier": "",
"privileges": null,
"instructedAmount": {
"currency": "EUR",
"amount": "723.50"
},
"creditorName": "Merchant A",
"creditorAccount": {
"bic":"ABCIDEFFXXX",
"iban": "DE02100100109307118603"
},
"datatypes": null,
"remittanceInformationUnstructured": "Ref Number Merchant"
}]'
Token request with RAR
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=clientRAR' \
--data-urlencode 'client_secret=asfasdfawqdewq' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=9CowFNlxxbTcTtiMFWuMlVmLKJBa6zR_fkrQ2w7xWzk.DKAX-67L3PqrBaeVmLGhkjbFI5DkOPn4dYqJdq8_6maAUXRZG4ajyIUH4VouwcLYsbUAXlMpIxhESAXJbHvzAQ' \
--data-urlencode 'redirect_uri=https://www.google.com'
OpenID for Verifiable Credential Issuance
- OpenID for Verifiable Credential Issuance is an extension of the OpenID standard. It enables users to log in to websites and applications by using their digital credentials, such as Verifiable Credentials. This allows users to access services and information that are secured by their digital credentials, without having to remember multiple usernames and passwords.
Configuring provider.yml
- The definition configuration defines a new grant_type
urn:ietf:params:oauth:grant-type:token-exchange
.
# Copyright contributors to the IBM Verify Identity Access OIDC Provider Resources project
version: 24.12
logging:
level: debug
definition:
id: 1
name: OIDC Definition
grant_types:
- authorization_code
- password
- client_credentials
- implicit
- refresh_token
- urn:ietf:params:oauth:grant-type:token-exchange
- urn:ietf:params:oauth:grant-type:pre-authorized_code
pre_mappingrule_id: isvaop_pretoken # Pre-Token mapping rule ID.
post_mappingrule_id: isvaop_posttoken
base_url: https://isvaop.ibm.com:445/isvaop
token_settings: # Token Settings
issuer: https://isvaop.ibm.com # OP's issuer URI.
signing_alg: PS256 # Signing algorithm for ID token generated.
signing_keystore: isvaop_signing # Signing keystore name.
signing_keylabel: jwtsigning # Signing key label.
attribute_map: # Attribute mapping to resolve claims. also refer to attributesources.yml
surname: surname
pre_auth_settings:
pre_authorized_code_lifetime_in_secs: 1800
require_transaction_code: true
transaction_code_charset: 123456789
transaction_code_length: 4
credential_issuer_jwks_uri_map:
https://www.ibm.com: https://test.com/jwks
https://test.com: https://test.com/default/jwks
server:
ssl:
key: ks:isvaop_keys/httpserverkey
certificate: ks:isvaop_keys/httpservercert
jwks:
signing_keystore: isvaop_signing
secrets:
obf_key: "ENC:iUt+3MzCntxSL2FPTUuJqER79UaiRSApMz3cbgJm4yzuiv6H7KN8ADsamX6+Qre1oTsATjnb1bJ0Lmi7WWfxWeGT477yqqvgVayFlCDIFzZeNkdINjASfTE3B+/3Sm9YjIYuWtZdySiXeydhJXSiOGU9osdA9g2BZXR4eMrXNutCuaSvFH6MY+TyOH5q15vy6vEWOebJQHrnug0A8rN6NF8G8XaxCe/+yqH57jJpdhm0N7iUydIYOBOQ1wDgCc8nRMWkQqlkcRhDZvLLAIlhoshYvo06ubyryt8/vv/0AvTLq9AIiQoL8CtYLr+SNZlzWe4CnHYZdO9S+AIrUOVORw=="
enc_key: "@keys/private.pem"
Configuring the static client
- A new property
act_as_credential_issuer
to indicates if the client act as credential issuer client
# Copyright contributors to the IBM Verify Identity Access OIDC Provider Resources project
clients:
- client_id: clientVerifiableCredential
client_secret: "OBF:U2FsdGVkX19iBhlwc53QkybjO6RjFHhSbz4VRudYHA=" # Client secret that is used for client authentication and/or JWT signing/encryption. `OBF:` indicates obfuscated string.
client_name: clientVerifiableCredential # Name of the client.
client_id_issued_at: 1642399207 # Timestamp (in seconds) from when the client is created.
enabled: true # Set to `true` to enable this client
grant_types: # Grant type that the client is allowed to use at the token endpoint.
- authorization_code
- password
- client_credentials
- implicit
- refresh_token
- urn:openid:params:grant-type:ciba
- urn:ietf:params:oauth:grant-type:token-exchange
- urn:ietf:params:oauth:grant-type:pre-authorized_code
response_types: # Response type that the client is allowed to use at the authorization endpoint.
- code id_token
- code
- code token
- none
- code token id_token
redirect_uris: # Redirection URI strings for use in redirect-based flows such as the authorization code and implicit flows.
- https://www.rp.com/redirect
act_as_credential_issuer: true
authorization_details_types: # Supported authorization details type
- openid_credential
request_uris: # Request URIs that are pre-registered by the Relying Party for use at the OIDC Provider.
- https://www.rp.com/request/test.jwt
scopes: # A list of scope values that the client can use when requesting access tokens.
- cdr:registration
- openid
- profile
jwks_uri: https://www.rp.com/oidc/endpoint/default/jwks
id_token_signed_response_alg: PS512
token_endpoint_auth_method: client_secret_post
token_exchange_settings:
client_groups:
- benefits
- insurance
supported_subject_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
supported_actor_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
- urn:x-oath:params:oauth:token-type:device-secret
supported_requested_token_types:
- urn:ietf:params:oauth:token-type:access_token
- urn:ietf:params:oauth:token-type:refresh_token
- urn:ietf:params:oauth:token-type:id_token
Dynamic client request
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/register' \
--header 'Content-Type: application/json' \
--data '{
"redirect_uris": [
"https://www.google.com"
],
"grant_types": [
"authorization_code",
"client_credentials"
],
"response_types": [
"code"
],
"authorization_details_types":["account_information","openid_credential"],
"act_as_credential_issuer":true,
"token_endpoint_auth_method": "client_secret_post"
}'
Pre-Authorized code Flow
- In the context of verifiable credential issuance, a pre-authorized code is used to authorize the client application to issue verifiable credentials on behalf of the user. This allows the user to grant the application permission to access their personal data and issue verifiable credentials without sharing their credentials with the issuer. The pre-authorized code is an important component of the pre-authorized code flow in OAuth 2.0, and it enables secure and seamless access to personal data and verifiable credentials.
- Before initiating the flow with the Wallet, the Credential Issuer must perform preparatory steps, such as, end-user authentication and authorization. Consequently, the Credential Issuer sends the Pre-Authorized Code to the Wallet. This flow does not use the Authorization Endpoint. Instead, the Wallet exchanges the Pre-Authorized Code for the Access Token directly at the Token Endpoint. The Access Token is subsequently used to request Credential issuance at the Credential Endpoint.
- User information is collected, and the pre-authorized code is generated.
- This is a sequence diagram once the Pre-Authorized code is received by the Credential issuer.
Configuring mapping rule
- A new mapping rule called preauth_userauth.js is invoked to perform user authentication and authorization. It can be an LDAP lookup or HTTPCallout.
- A callbackURL is published as a part of the mapping rule invocation. After the user is authenticated, the callbackURL can be invoked with the status to indicate the status (success or failure).
- preauth_userauth.js sample
/**
* Copyright contributors to the IBM Verify Identity Access OIDC Provider Resources project
*/
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.OAuthMappingExtUtils);
importClass(Packages.com.ibm.security.access.httpclient.HttpClient);
IDMappingExtUtils.traceString("CallbackURL$$" + preauth.getCallbackURL() + '$$');
var payload = preauth.getPayload();
if(payload["type"] == "http"){
var headers = new Headers();
//Perform a HTTP Callout, if it comes back successfully, user metadata is populated.
headers.addHeader('Content-Type','application/json');
var payload = preauth.getPayload();
payload["callbackURL"] = preauth.getCallbackURL()
IDMappingExtUtils.traceString("payload: " + JSON.stringify(payload));
let resp = HttpClientV2.httpPost("https://host.docker.internal/userauth", headers, JSON.stringify(payload), null, null, null, null, null, null, null, null, true, null)
if (resp.hasError()) {//getError
IDMappingExtUtils.traceString("resp.getError(): " + resp.getError());
} else {
IDMappingExtUtils.traceString("StatusCode: " + resp.getCode());
if(resp.getCode() == 200){
IDMappingExtUtils.traceString("hERE: ");
var metadata = {};
metadata.uid = "prabbit";
metadata.given_name = "peter";
metadata.family_name = "rabbit";
metadata.preferred_username = "[email protected]";
IDMappingExtUtils.traceString("approved: ");
preauth.approved(metadata);
}
}
}
//IDMappingExtUtils.traceString("preauth.isCallback(): " + preauth.isCallback());
else{
if (preauth.isCallback()) {
if (payload.status === "approved") {
var metadata = {};
metadata.uid = "prabbit";
metadata.given_name = "peter";
metadata.family_name = "rabbit";
metadata.preferred_username = "[email protected]";
preauth.approved(metadata);
} else if (payload.status === "denied") {
IDMappingExtUtils.traceString("denied " );
preauth.denied();
} else {
OAuthMappingExtUtils.throwSTSCustomUserMessageException("Expecting authentication status", 400, "invalid_request");
}
} else if (preauth.isCallback() == undefined){
IDMappingExtUtils.traceString("else if " );
if (payload.status === "undefinedapproved") {
var metadata = {};
metadata.uid = "prabbit";
metadata.given_name = "peter";
metadata.family_name = "rabbit";
metadata.preferred_username = "[email protected]";
preauth.approved(metadata);
} else if(payload.status === "denied"){
IDMappingExtUtils.traceString("denied " );
preauth.denied();
}
else{
//A callback url is published, once user is authenticated successfully, the callback URL can be called with the approved status to complete the flow.
IDMappingExtUtils.traceString("pending " );
IDMappingExtUtils.traceString("CallbackURL:::" + preauth.getCallbackURL() + ':::');
preauth.pending();
}
} else {
IDMappingExtUtils.traceString("else " );
IDMappingExtUtils.traceString("$$CallbackURL" + preauth.getCallbackURL() + '$$');
preauth.pending(); // for initial request, we return pending first
}
}
- preauth_notifytxcode.js sample
- This mapping rule is invoked to be able to deliver the transaction code to the user.
importClass(Packages.com.tivoli.am.fim.trustserver.sts.utilities.IDMappingExtUtils);
importClass(Packages.com.ibm.security.access.httpclient.HttpClient);
var headers = new Headers();
headers.addHeader('Content-Type','application/json');
var payload = preauth.getTransactionCode();
payload["callbackURL"] = preauth.getCallbackURL()
IDMappingExtUtils.traceString("payload: " + JSON.stringify(payload));
let resp = HttpClientV2.httpPost("https://gateway.sms.com", headers, JSON.stringify(payload), null, null, null, null, null, null, null, null, true, null)
if (resp.hasError()) {//getError
IDMappingExtUtils.traceString("resp.getError(): " + resp.getError());
}
IDMappingExtUtils.traceString("CODE$$" + preauth.getTransactionCode()+"$");
Preauthorized request
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/preauth' \
--header 'Content-Type: application/json' \
--data-raw '{
"user.email": "[email protected]"
}'
- The mapping rule is triggered, and a callback URL is now available. After the user is authenticated, the callback URL needs to be invoked.
Callback request
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/preauth?stateId=b1444419-81df-4377-9a0d-5af4d10b64ae' \
--header 'Content-Type: application/json' \
--data '{
"status": "approved"
}'
- If the status is approved in the mapping rule, user-related data can be populated.
- The transaction code is now generated and the preauth_notifytxcode.js is invoked. The transaction code can be sent via an SMS gateway to the end-user.
Token request
curl --location 'https://isvaop.ibm.com:445/isvaop/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=clientVerifiableCredential' \
--data-urlencode 'client_secret=asfasdfawqdewq' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code' \
--data-urlencode 'scope=openid tpin' \
--data-urlencode 'pre-authorized_code=0QssrwwbDhAT5lfqiNupYQynknXkzWhE9B7_euPFI4Q.jJ2DPI-p7zFXudQ82LeS__cG9m8KYXnF_EPjP6Zze3zU--4P2L0jFhILqEEuQTrmOBvlnasirqWJf77nRE8e7w' \
--data-urlencode 'redirect_uri=https://www.google.com' \
--data-urlencode 'authorization_details=[{
"type": "openid_credential",
"credential_configuration_id": "ABCDEFGHIJKLMNOPQRS",
"claims": {
"org.iso.18013.5.1": {
"given_name": {},
"family_name": {},
"birth_date": {}
},
"org.iso.18013.5.1.aamva": {
"organ_donor": {}
}
}
}]' \
--data-urlencode 'tx_code=6127'
Token response
{
"access_token": "YGoE9kZdoYea0C4CQz64inGRgZa7YXYA32a4Xr5_wYo.Hl0Kba71Z5hXAfxBTMMmFBJRmGVV6TPc2gpG4pifoxuY2qRKa3LesU3DmXjTxYp0jW0GEYceYolvhBBiBZWZaQ",
"authorization_details": [
{
"actions": null,
"claims": {
"org.iso.18013.5.1": {
"birth_date": {
"date": "13th Jan 1956"
},
"family_name": {
"name": "Doe"
},
"given_name": {
"name": "John"
}
},
"org.iso.18013.5.1.aamva": {
"organ_donor": {
"name": "Jane Doe"
}
}
},
"credential_configuration_id": "ABCDEFGHIJKLMNOPQRS",
"datatypes": null,
"identifier": "",
"locations": null,
"privileges": null,
"type": "openid_credential"
}
],
"c_nonce": "WsRJdk9vGd_wJ-M344ElkerLhe0PgkgyTY3jY7EC_bI",
"c_nonce_expires_in": 3600,
"expires_in": 7200,
"refresh_token": "u6oy_uI6FRSNMMDfd9rwDnws9ddyYT8EabxB3IHrrjc.f1aXOxYhNfauCSdx50vusC__AxT_LZzSt9z-hHcjlojJBDJeQLqTnF094AKf0Kx_HZwU3JQbcpElgZPknHLt7g",
"scope": "openid",
"token_type": "bearer"
}
Note
RAR and VC require
Updated 3 days ago