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.
2006

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.
866
  • 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.
822

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