Authorization Token

Prerequisites

For the example we assume the following environment, as noted in Introduction and Authentication Token:

clientId        <a-client-id>
clientSecret    *****

Assume a registered Data Asset configured with all available Authorization Scopes: READ, EDIT, DELETE, TRADE.

id      f1fbe38e-e143-45d4-a757-f11d18e14d85
name    example-pistis-asset

Example policies for testing that:

  • authorize anyone with PISTIS_USER role with the READ scope (thus all testing user will be granted with READ scope)
  • exclusively allow user pdt-01 to grant EDIT, DELETE, TRADE scopes

Receive authorization for the asset

Initially, we should obtain the access_token of the user via the request described in Authentication Token (section: Receive Token)

The authorization request for the specified Data Asset can be realized via:

curl --location 'https://auth.pistis-market.eu/realms/PISTIS/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer ${access_token}' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \
--data-urlencode 'audience=resource-server' \
--data-urlencode 'permission=f1fbe38e-e143-45d4-a757-f11d18e14d85'

where as:

  • resource-server is the name of the dedicated client within Keycloak for assets (resources) authorization
  • ${access_token} should be replaced by the access_token as it is received in previous step
  • asset in the request is represented by the permission parameter and can be either asset name (example-pistis-asset) or asset id (f1fbe38e-e143-45d4-a757-f11d18e14d85)

Sample snippet with asset represented with asset name:

curl --location 'https://auth.pistis-market.eu/auth/realms/PISTIS/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer ${access_token}' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \
--data-urlencode 'audience=resource-server' \
--data-urlencode 'permission=example-pistis-asset'

Query for specific scope

permission parameter can be formulated like: {asset id}#{Scope} for example: 8852867a-d674-4918-903c-412493a2c2c7#READ or {asset name}#{Scope}, for example: example-pistis-asset#READ

Multiple scopes can be separated using commas.

Sample snippet querying for a specific scope:

curl --location 'https://auth.pistis-market.eu/auth/realms/PISTIS/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer ${access_token}' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \
--data-urlencode 'audience=resource-server' \
--data-urlencode 'permission=example-pistis-asset#READ'

Sample snippet querying for a specific set of scopes:

curl --location 'https://auth.pistis-market.eu/auth/realms/PISTIS/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer ${access_token}' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \
--data-urlencode 'audience=resource-server' \
--data-urlencode 'permission=example-pistis-asset#READ,TRADE'

Authorization response modes

If parameter response_mode is specified to decision in the request, we will receive 200 OK if the requested operation is allowed or 403 Forbidden otherwise.

Sample snippet querying in decision mode:

curl --location 'https://auth.pistis-market.eu/auth/realms/PISTIS/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer ${access_token}' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:uma-ticket' \
--data-urlencode 'audience=resource-server' \
--data-urlencode 'permission=example-pistis-asset#READ' \
--data-urlencode 'response_mode=decision'

Unauthorized response

If user has no authority on the requested asset the response will have 403 Forbidden status, with payload:

{
    "error": "access_denied",
    "error_description": "not_authorized"
}

Authorization examples

The response of such an authorization request will follow the OpenIDC with a response:

{
    "upgraded": false,
    "access_token": "",
    "expires_in": 35999,
    "refresh_expires_in": 35999,
    "refresh_token": "",
    "token_type": "Bearer",
    "not-before-policy": 0
}

where access_token is the signed JWT containing the authorization information. When the access_token will be decompiled, it will contain an authorization section, as illustrated in the following examples.

Example 1

User 00-test is granted with READ scope for the asset.

{
  ......
  "authorization": {
    "permissions": [
      {
        "scopes": [
          "READ"
        ],
        "rsid": "f1fbe38e-e143-45d4-a757-f11d18e14d85",
        "rsname": "example-pistis-asset"
      }
    ]
  },
  ....
}

Example 2

User pdt-01 is granted all available scopes for the asset.

{
  ......
  "authorization": {
    "permissions": [
      {
        "scopes": [
          "READ",
          "TRADE",
          "DELETE",
          "EDIT"
        ],
        "rsid": "f1fbe38e-e143-45d4-a757-f11d18e14d85",
        "rsname": "example-pistis-asset"
      }
    ]
  },
  ....
}

Handy visualization script for Postman

The following script can be included as a test operation in a Postman request to directly decompile permissions included in the resulted access_token of the JWT claims:

var jsonData = pm.response.json();
pm.environment.set("jwt", jsonData.access_token);

 function parseJwt (token,part) {
   var base64Url = token.split('.')[part];
   var words = CryptoJS.enc.Base64.parse(base64Url);
   var jsonPayload = CryptoJS.enc.Utf8.stringify(words);
   return  JSON.parse(jsonPayload);
};

var jwtInfo ={};
jwtInfo.size = jsonData.access_token.length;
jwtInfo.header = parseJwt(jsonData.access_token,0);
jwtInfo.payload = parseJwt(jsonData.access_token,1);
jwtInfo.signature = jsonData.access_token.split('.')[2];
jwtInfo.expires = ((jwtInfo.payload.exp-Date.now().valueOf()/1000)/60).toFixed(1);
console.log(jwtInfo);

var auth = jwtInfo.payload.authorization;
console.log(auth);


var template = `
    <style type="text/css">
        div {white-space: pre-wrap;}
    </style>
    <div>
        {{response}}
    </div>
`;

const payload = JSON.stringify(auth, null, 28);

 pm.visualizer.set(template, {
     response: payload.trim()
 });