How to add extra properties to an access token


Preface


On receiving API requests (with access tokens) from clients, resource servers determine if the requests are allowed, and how to process them, by referring information associated with the tokens. Typical kinds of information include the following: status of the token (active / expired), who (resource owner) granted what access (scope) to whom (client). In some cases, the resource servers need to obtain other related information from an authorization server. 

Authlete enables an authorization server to associate arbitrary properties with either an access token or authorization code. The authorization server can easily share the properties with resource servers so that they can consume such information for its authorization enforcement as well as making a response.

You can prevent unnecessary information disclosure as the sharing of properties can be achieved by not using clients as an intermediary.

Use cases


1. Controlling a money transfer API

 
Let's assume you would like to develop a money transfer API that can process specific transaction like "send $50 to ABC shop."

You could implement such function by creating a "send-50dollar-to-abcshop" scope, but it hardly works as you would have to prepare a lot of scopes that are multiplied with recipients and amounts.

With the properties feature of Authlete, The authorization server can associate the money transfer information (or its handle, if database manages the actual information) with an access token to be issued to a client. The resource server, which hosts the money transfer API, receives an API request with the access token from the client, asks Authlete's introspection API to provide the properties along with details of the token, and then determines if the money transfer request is allowed to proceed.
extra-properties-money-transfer.png 105.92 KB


2. Role based access control


When a resource server receives an API request with an access token, it would like to know details of the token, not only user identifier but also groups and roles of the user.

A simple solution is, that the resource server makes an introspection request to Authlete, gets the user identifier ("subject") and makes a query to another database to find such groups/roles information.

Again, Authlete's properties feature makes the implementation simpler. The authorization server can associate the groups/roles with the access token to be provided to the client, and the resource server can find the values from the access token included in an API request from the client. The resource server doesn't need to communicate with the database.
extra-properties-rbac.png 103.56 KB


How it works


This section describes examples on how to set and get properties.

“Property” data type


Authlete defines Property data type that represents an arbitrary set of attributes associated with either an access token or an authorization code. The Property data type is a JSON object that contains the following entries.
Name
Type
Description
key
string
A key of the property
value
string
A value of the property
hidden
boolean
A flag that indicates if the property is hidden from clients
  • true: hidden from clients
  • false: not hidden from clients i.e. they can see the content


For example, a property whose key and value are example_key and example_value respectively and that is not hidden from clients would be represented as a  JSON object as follows.

{
  "key":"example_key",
  "value":"example_value",
  "hidden":false
}

Associating properties


Associating properties with an access token and/or an authorization code will be done by an authorization server at the following steps.

Providing an authorization code and/or an access token through its authorization endpoint


An authorization server sets properties to a request to Authlete's /auth/authorization/issue API. Authlete associates the properties with the new authorization code / the access token and provide content of a token response including the code / the token.

The following is an example using curl. (folded for readability)

  • Request
curl -s -X POST .../auth/authorization/issue 
 -u ...:... 
 -H 'Content-type: application/json'
 -d '{"subject":"<subject>",
      "ticket":"<ticket>",
      "properties":[
        {"key":"example_key",
         "value":"example_value",
         "hidden":true}
        ]
     }'

  • Response
{
  "type": "authorizationIssueResponse",
  "resultCode": "A040001",
  "resultMessage": "[A040001] The authorization request was processed 
    successfully.",
  "accessTokenDuration": 0,
  "accessTokenExpiresAt": 0,
  "action": "LOCATION",
  "authorizationCode": "...",
  "responseContent":
    "https://client.example.org/cb/example.com?code=..."



Providing an access token through a token endpoint


An authorization server sets properties to a request to Authlete's /auth/token API. Authlete associates the properties with the new access token and provide content of a token response including the token.

The following is an example using curl. (folded for readability)

  • Request
curl -s -X POST .../auth/token 
 -u ...:...
 -H 'Content-type: application/json'
 -d '{"clientId":"<clientId>",
      "clientSecret":"<clientSecret>",
      "parameters":
        "redirect_uri=https://client.example.org/cb/example.com
         &grant_type=authorization_code
         &code=...",
      "properties":[
        {"key":"example_key",
         "value":"example_value",
         "hidden":false}
        ]
    }'

  • Response
{
  "type": "tokenResponse",
  "resultCode": "A050001",
  "resultMessage":
    "[A050001] The token request (grant_type=authorization_code) was processed
     successfully.",
  "accessToken": "...",
  "action": "OK",
...
  "properties": [
    {
      "hidden": false,
      "key": "example_key",
      "value": "example_value"
    }
  ],
  "refreshToken": "...",
  "responseContent":
    "{\"access_token\":\"...\",
      \"refresh_token\":\"...\",
      \"scope\":\"payment\",
      \"token_type\":\"Bearer\",
      \"expires_in\":300,
      \"example_key\":\"example_value\"
     }",
  "subject": "<subject>"
}


Obtaining properties


By sending an access token (extracted from an API request from a client) to Authlete's /auth/introspection API, an resource server receives a response that would contain properties.

The following is an example using curl. (folded for readability)

  • Request
curl -s -X POST .../auth/introspection 
 -u ...:...
 -H 'Content-type: application/json'
 -d '{"token":"<accessToken>"}'

  • Response
{
  "clientId" : <clientId>,
  "properties" : [
    {
      "key":"example_key",
      "value":"example_value",
      "hidden" : false
    }
  ],
  "action" : "OK",
  "resultCode" : "A056001",
  "expiresAt" : 1565847795000,
  "subject" : "<subject>",
  "type" : "introspectionResponse",
  "refreshable" : true,
  "usable" : true,
  "existent" : true,
  "resultMessage" : "[A056001] The access token is valid.",
  "responseContent" : "Bearer error=\"invalid_request\""
...
}

Notes


Reserved values for "key"


The following values are not applicable for "key" of properties, as RFC 6749 and OpenID Connect Core 1.0 have reserved the names for parameters which may be included in a response from an authorization server. Authlete discards them if they are specified. 
  • access_token
  • token_type
  • expires_in
  • refresh_token
  • scope
  • error
  • error_description
  • error_uri
  • id_token

Type of "value"


String is the only allowed type of "value." Neither boolean nor array can be specified.

Size of properties


Size of properties is limited. Properties are saved into the database on the server side after going through the steps described below. 
  1. Converted to a two-dimensional array (e.g. [["example_parameter","example_value",null]]). The value of hidden is converted to either null or an empty string. They mean false and true, respectively.
  2. Converted to JSON (e.g. "[[\"example_parameter\":\"example_value\",null]]")
  3. Encrypted by AES/CBC/PKCS5Padding
  4. Encoded by base64url
  5. If the length of the resultant base64url string generated by the above steps exceeds 65535, an error occurs.

See also


How did we do with this article?