Rich Authorization Requests

Introduction


The mechanism introduced by OAuth 2 Authorization Framework specification for representing the permissions granted to a third party by a resource owner is the scope list. One can assign a specific semantic to a scope to represent a permission or an optional.

For instance: OpenID Connect specification defines the "openid" scope as well as "profile" among others. While "profile" grants to 3rd party access to specific attributes of the user profile, the "openid" scope has a different semantic: grant the id token generation and the access to userinfo endpoint,

With the broad usage of OAuth 2, new use cases rises and as such new technical solutions are required.

The Rich Authorization Requests draft (or RAR for short), address the scenarios where 3rd parties are required to express an intent with more context for user approval, like online payments, file sharing. health exams, etc.

This article is about the support for RAR on Authlete and how you can use it to represent fine grained permissions.

Rich Authorization Request 


RAR defines a common JSON structure for the finer grained permissions, where each permission has a "type" attribute, optionally the attributes: "locations", "actions", "datatypes", "identifier" and "privileges" and attributes defined by the parties. You can check the structure description under Authorization data elements section.

The idea is that the authorization server, or the ecosystem that the AS is in,  will define different "types" identifiers and theirs semantics: what do they represent, their structure, their meaning to end users and associated to the other attributes, it will precisely define the permission to be requested to end user.

The "locations" attribute has the same concept of the Resource Idicators mechanism, where the location specify a resource server uri that the permission is about. With the attribute "identifier" the specific resource can be pointed to when requesting permissions. While the "locations" indicate a branch of resources, the "identifier" points to a single resource, for short.

The "actions" is a big step forward as it can represent for instance: the action on a filesystem, the action on the bank account, an action on medical device, an act on an appliance, a permission on a database, etc.

The "datatypes" and "privileges" can be used to represent specifics of the entitlements that is been requested.

Configuration


The support on Authlete for the RAR is enabled by default. But the authorization types are not granted by default. It must be configured on service level and granted to individual clients.


Service level


Administrators is required to configure is the list of authorization "types" that are supported, that is done on Service Owner Console under Authorization tab. The list of supported types is a set of types that clients can requests, but it is not granted automatically to any client.

List of supported authorization types by a service



Client level

 
On the Developer Console, the administrator can grant to individual clients the set of requestable authorization types by the client under Authorization tab.

List of authorization types that a client can request


Authorization request


The usage of RAR does not restrict if the request is pushed or not or if the Requests Objects are used or not. There are constraints in place for those mechanisms: if the RAR request is very large, it will require clients to use PAR, if we need to make tamper evident, we need to use JAR.

For instance, the RAR can be urlencoded and sent in a authorization request like below:
curl --request POST 'https://api.authlete.com/api/auth/authorization' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic OXXXXXXXXXX=' \
--data '{ 
    "parameters": "client_id=4025660683512920&
     scope=openid&
     response_type=code&
     redirect_uri=https%3A%2F%2Fmobile.example.com%2Fcb&
     code_challenge=NcCW6zMwKWy5Mya8jopzE1SVeTBJBAHH1jU7TPpYK9A&
     code_challenge_method=S256&
     authorization_details=%5B%7B%22type%22%3A%20%22customer_information%22%2C%22locations%22%3A%20%5B%22https%3A%2F%2Fexample.com%2Fcustomers%22%2C%5D%2C%22actions%22%3A%5B%22read%22%2C%22write%22%5D%2C%22datatypes%22%3A%5B%22contacts%22%2C%22photos%22%5D%7D%5D" }'

The same RAR content can be wrapped on a JAR as the sample below. Where the authorization request is echoed back to the authorization server is order to collect the user approval.

curl --request POST 'https://api.authlete.com/api/auth/authorization' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic OXXXXXX8=' \
--data-raw '{ "parameters": "client_id=4025658857453025&request=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InNpZzEifQ.eyJpc3MiOiI0MDI1NjU4ODU3NDUzMDI1IiwiYXVkIjoiaHR0cHM6Ly9hdXRobGV0ZS5jb20iLCJyZXNwb25zZV90eXBlIjoiY29kZSIsImNsaWVudF9pZCI6IjQwMjU2NTg4NTc0NTMwMjUiLCJyZWRpcmVjdF91cmkiOiJodHRwczovL21vYmlsZS5leGFtcGxlLmNvbS9jYiIsInNjb3BlIjoib3BlbmlkIiwic3RhdGUiOiJhZjBpZmpzbGRraiIsImNvZGVfY2hhbGxlbmdlIjoiQW9OM29NcVFvUVF1RGhoQmc2VTF2Y0ljbXRtQ19QWm9UMGNoVEVSVktFZyIsImNvZGVfY2hhbGxlbmdlX21ldGhvZCI6IlMyNTYiLCJhdXRob3JpemF0aW9uX2RldGFpbHMiOlt7InR5cGUiOiJjdXN0b21lcl9pbmZvcm1hdGlvbiIsImxvY2F0aW9ucyI6WyJodHRwczovL2V4YW1wbGUuY29tL2N1c3RvbWVycyJdLCJhY3Rpb25zIjpbInJlYWQiLCJ3cml0ZSJdLCJkYXRhdHlwZXMiOlsiY29udGFjdHMiLCJwaG90b3MiXX1dLCJpYXQiOjE2Mjg1MzE0NDQsIm5iZiI6MTYyODUzMTQ0NCwiZXhwIjoxNjI4NTMyMDQ5LCJqdGkiOiI4WjJEbGpCaUZVckpnTUt3bThiQ3EifQ.PIxVI2GFWi7B_frRfLg9r8AWEz7HGeopMeQo7MLYVEMGpOdoPkt5piBrLXI7PPI7ohrUmhxd-B4kZfm4WfkKH5qSub4A_mdd6pBpTWacBgfVQDIOvzE1yPrawCDEWQn2xgdYd1G-KM6pk8rDngOMEfaBbnoJ5C9krQtgYMHGbDIScgm8Y5AHf5aEF41FboZI67BlvbzXdxcJEPvB2zLGwV9twMrJ07OeRX0NVpIamhhEgfMQ87FyOsPVx9bqYUPN_VjwgB8lkKgrCdIkc9jPs2mQkpUbx0AIg8Pfmwyw0F5Vih7tgBbpb1LlwNgW36La3DPtTY9xSZ7SQGcyGxteIA" }'
{
    "type": "authorizationResponse",
    "resultCode": "A004001",
    "resultMessage": "[A004001] Authlete has successfully issued a ticket to the service (API Key = 979748525706) for the authorization request from the client (ID = 4025658857453025). [response_type=code, openid=true]",
    "action": "INTERACTION",
    "authorizationDetails": {
        "elements": [
            {
                "actions": [
                    "read",
                    "write"
                ],
                "dataTypes": [
                    "contacts",
                    "photos"
                ],
                "locations": [
                    "https://example.com/customers"
                ],
                "type": "customer_information"
            }
        ]
    },
    ...
    "requestObjectPayload": "{\"iss\":\"4025658857453025\",\"aud\":\"https://authlete.com\",\"response_type\":\"code\",\"client_id\":\"4025658857453025\",\"redirect_uri\":\"https://mobile.example.com/cb\",\"scope\":\"openid\",\"state\":\"af0ifjsldkj\",\"code_challenge\":\"AoN3oMqQoQQuDhhBg6U1vcIcmtmC_PZoT0chTERVKEg\",\"code_challenge_method\":\"S256\",\"authorization_details\":[{\"type\":\"customer_information\",\"locations\":[\"https://example.com/customers\"],\"actions\":[\"read\",\"write\"],\"datatypes\":[\"contacts\",\"photos\"]}],\"iat\":1628531444,\"nbf\":1628531444,\"exp\":1628532049,\"jti\":\"8Z2DljBiFUrJgMKwm8bCq\"}",
    "ticket": "xTZCagNjVJUltVS-WD7CKZr1fp0zeFTAAva86Rmzuow"
}


Token


After the user has approved, the authorization code is generated and sent to client, it will invoke the token endpoint authenticating itself (if required) and Authlete will generate the access token and id token (if using openid).

Note that as Resource Indicators, the grant is not encoded into the id token.

curl --request POST 'https://api.authlete.com/api/auth/token' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic OXXXXXXXXXXXXXXXX8=' \
--data '{ "parameters": "grant_type=authorization_code&code=wkPCpsu-HsMDeaNFBI78LydnmW7IyadBLloa3Mn7ZzM&redirect_uri=https%3A%2F%2Fmobile.example.com%2Fcb&code_verifier=ZhoMDipQfa7iMabyG-wSQ83ATy1GCVvE8Lh3SlDZdNo",
   "clientId" : "4025658857453025"
}'
{
    "type": "tokenResponse",
    "resultCode": "A050001",
    "resultMessage": "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
    "accessToken": "Q4nS7518ZP4W0JaabMGJRBYGj919SY1IyxuDHZUw_Qc",
    "action": "OK",
    "authorizationDetails": {
        "elements": [
            {
                "actions": [
                    "read",
                    "write"
                ],
                "dataTypes": [
                    "contacts",
                    "photos"
                ],
                "locations": [
                    "https://example.com/customers"
                ],
                "type": "customer_information"
            }
        ]
    },
    ...
    "idToken": "eyJraWQiOiIzIiwiYWxnIjoiUlMyNTYifQ.eyJjcGYiOiIzOTY3ODczNjY4MyIsIm5hbWUiOiJDYXNleSBQdXJkeSIsImVtYWlsIjoiQ2lhcmFfU3BvcmVyQGdtYWlsLmNvbSIsImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwic3ViIjoiQ2lhcmFfU3BvcmVyQGdtYWlsLmNvbSIsImF1ZCI6WyI0MDI1NjU4ODU3NDUzMDI1Il0sImV4cCI6MjUzNDAyMTI4MDAwLCJpYXQiOjE2Mjg1MzIzMjAsInNfaGFzaCI6ImJPaHRYOEY3M0lNalNQZVZBcXh5VFEifQ.Vrc3BcXtnAUtrnfSOPWagTWnV_SB0DL5cEp535pt33n8S4op94GSM51waTS6OcoZ-R7YKQ0l7FrMGxFl6MGFd6Wn_FjHNyu7J2TmEH9sARZTW7ZmWQo5euWkLx6NjgMAp_9LsjDXwB8Cjr3ujkVt3DdKRg6fkETwgGYYkEIrfdtRO_yJLANunHG-wm92TzOd44xXaTBF4bBinBcZFUrpr2nCPRM0rrUmBLwqtBeJyuUIPFnLHGsIaRE14wUTJ7BD1RONvAtAFC3k2K7ayVUbxfJYbSQtvFEdtLueSgNWsHZBXd-JG9eku44BL2m4_pwvD_eCzXGvP40BnuSFPKXjjw",
    "responseContent": "{\"access_token\":\"Q4nS7518ZP4W0JaabMGJRBYGj919SY1IyxuDHZUw_Qc\",\"authorization_details\":[{\"type\":\"customer_information\",\"locations\":[\"https://example.com/customers\"],\"actions\":[\"read\",\"write\"],\"datatypes\":[\"contacts\",\"photos\"]}],\"scope\":\"openid\",\"id_token\":\"eyJraWQiOiIzIiwiYWxnIjoiUlMyNTYifQ.eyJjcGYiOiIzOTY3ODczNjY4MyIsIm5hbWUiOiJDYXNleSBQdXJkeSIsImVtYWlsIjoiQ2lhcmFfU3BvcmVyQGdtYWlsLmNvbSIsImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwic3ViIjoiQ2lhcmFfU3BvcmVyQGdtYWlsLmNvbSIsImF1ZCI6WyI0MDI1NjU4ODU3NDUzMDI1Il0sImV4cCI6MjUzNDAyMTI4MDAwLCJpYXQiOjE2Mjg1MzIzMjAsInNfaGFzaCI6ImJPaHRYOEY3M0lNalNQZVZBcXh5VFEifQ.Vrc3BcXtnAUtrnfSOPWagTWnV_SB0DL5cEp535pt33n8S4op94GSM51waTS6OcoZ-R7YKQ0l7FrMGxFl6MGFd6Wn_FjHNyu7J2TmEH9sARZTW7ZmWQo5euWkLx6NjgMAp_9LsjDXwB8Cjr3ujkVt3DdKRg6fkETwgGYYkEIrfdtRO_yJLANunHG-wm92TzOd44xXaTBF4bBinBcZFUrpr2nCPRM0rrUmBLwqtBeJyuUIPFnLHGsIaRE14wUTJ7BD1RONvAtAFC3k2K7ayVUbxfJYbSQtvFEdtLueSgNWsHZBXd-JG9eku44BL2m4_pwvD_eCzXGvP40BnuSFPKXjjw\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
    ...
}


Introspect access token


When the resource server receives a call with the access token, it can use the introspection endpoint to discover the grants behind the access token and fulfill or vet the request of the api client.

curl --request POST 'https://api.authlete.com/api/auth/introspection/standard' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic OXXXXXXXXXXXXXXXXXX8=' \
--data '{ "parameters": "token=Q4nS7518ZP4W0JaabMGJRBYGj919SY1IyxuDHZUw_Qc"}'
{
    "type": "standardIntrospectionResponse",
    "resultCode": "A145001",
    "resultMessage": "[A145001] Introspection was performed successfully (type=access_token, active=true).",
    "action": "OK",
    "responseContent": "{
      \"sub\":\"Ciara_Sporer@gmail.com\",
      \"authorization_details\":[
             {\"type\":\"customer_information\",
              \"locations\":[\"https://example.com/customers\"],
              \"actions\":[\"read\",\"write\"],
              \"datatypes\":[\"contacts\",\"photos\"]}],
      \"scope\":\"openid\",
      \"iss\":\"https://authlete.com\",
      \"active\":true,
      \"token_type\":\"Bearer\",
      \"exp\":1628618721,
      \"client_id\":\"4025658857453025\"}"
}



How did we do with this article?