OAuth 2.0 rich authorisation requests (RAR)

Rich authorisation requests (RFC 9396) is an OAuth 2.0 extension for expressing the authorisation specific parameters of a request as a JSON object. It is intended as an alternative to the simple and widely used OAuth 2.0 scope parameter, which is a space separated string of keywords for an aspect of access to a protected resource.

The RAR JSON object objects must be typed and define several optional parameters for expressing an authorisation:

  • locations -- The resources for which access is requested, typically a single valued array with the URL of the resource server. Resembles the resource parameter in RFC 8707.

  • actions -- The actions to be performed at the resource, typically expressed as verbs.

  • datatypes -- The types of data requested from the resource.

  • identifier -- To identify a specific resource.

  • privileges -- The types or levels of access requested for the resource.

Example:

{
  "type" : "message_api_v1",
  "locations" : [ "https://api.example.com/messages" ],
  "actions" : [ "post", "get", "search" ]
}

Authorisation request

Example Java code for a rich authorisation request recreating the above example:

import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.pkce.*;
import com.nimbusds.oauth2.sdk.rar.*;
import java.net.*;
import java.util.*;

// For PKCE
CodeVerifier codeVerifier = new CodeVerifier();

// Compose the authorisation detail
AuthorizationDetail authzDetail = new AuthorizationDetail.Builder(
    new AuthorizationType("message_api_v1"))
    .locations(
        Collections.singletonList(
            new Location(URI.create("https://api.example.com/messages"))))
    .actions(
        Arrays.asList(
            new Action("read"),
            new Action("get"),
            new Action("search")))
    .build();

// Compose the OAuth 2.0 authorisation request
AuthorizationRequest request = new AuthorizationRequest.Builder(
    ResponseType.CODE,
    new ClientID("123"))
    .endpointURI(URI.create("https://demo.c2id.com/login"))
    .authorizationDetails(Collections.singletonList(authzDetail))
    .redirectionURI(URI.create("https://client.example.com/cb"))
    .codeChallenge(codeVerifier, CodeChallengeMethod.S256)
    .state(new State())
    .build();

// Print the request
System.out.println(request.toURI());

Example output:

https://demo.c2id.com/login?
&response_type=code
&client_id=123
authorization_details=%5B%7B%22locations%22%3A%5B%22https%3A%5C%2F%5C%2Fapi.example.com%5C%2Fmessages%22%5D%2C%22type%22%3A%22message_api_v1%22%2C%22actions%22%3A%5B%22read%22%2C%22get%22%2C%22search%22%5D%7D%5D
&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb
&code_challenge_method=S256
&code_challenge=fu8tw3VznKQBN4HFGVta4k8Nj2S4ta10vRU-vLK3DhQ
&state=6YrLp40CZiCoDNlR49-6T9jv6d1KUKJDBBfRBGpiyRE

The RAR package

The classes to build and parse authorization_details objects in a type-safe manner are located in the com.nimbusds.oauth2.sdk.rar package.

Example recreation of the authorisation detail in figure 2 of the standard:

JSONObject instructedAmount = new JSONObject();
instructedAmount.put("currency", "EUR");
instructedAmount.put("amount", "123.50");

JSONObject creditorAccount = new JSONObject();
creditorAccount.put("iban", "DE02100100109307118603");

AuthorizationDetail detail = new AuthorizationDetail.Builder(
    new AuthorizationType("payment_initiation"))
    .actions(Arrays.asList(
        new Action("initiate"),
        new Action("status"),
        new Action("cancel")))
    .locations(Collections.singletonList(
        new Location(URI.create("https://example.com/payments"))))
    .field("instructedAmount", instructedAmount)
    .field("creditorName", "Merchant A")
    .field("creditorAccount", creditorAccount)
    .field("remittanceInformationUnstructured", "Ref Number Merchant")
    .build();

Token request with authorization_details

Here is an example token request using the client credentials grant with an authorization_details parameter:

// The client credentials
ClientID clientID = new ClientID("123");
Secret clientSecret = new Secret("moof9Lo7nohXeutoosh1uz8kiiZahngi");

// Compose the authorisation detail
AuthorizationDetail authzDetail = new AuthorizationDetail.Builder(
    new AuthorizationType("message_api_v1"))
    .locations(
        Collections.singletonList(
            new Location(URI.create("https://api.example.com/messages"))))
    .actions(
        Arrays.asList(
            new Action("read"),
            new Action("get"),
            new Action("search")))
    .build();

TokenRequest request = new TokenRequest(
    URI.create("https://demo.c2id.com/token"),
    new ClientSecretBasic(new ClientID("123"), new Secret()),
    new ClientCredentialsGrant(new ClientID("123")),
    null, // no scope
    Collections.singletonList(authzDetail),
    null, // no resources
    null); // no custom params

// Make HTTP request
HTTPRequest httpRequest = request.toHTTPRequest();
HTTPResponse httpResponse = request.send();