Custom token response SPI

1. Introduction

The OAuth 2.0 framework (RFC 6749) allows for additional parameters to be sent in the access token response. This is used for instance by OpenID Connect to return its ID token to the relying party and by the new Rich Authorisation Requests (RAR) to include metadata about the token's capabilities.

Example access token response which includes RAR metadata:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache, no-store
Pragma: no-cache

   "access_token": "2YotnFZFEjr1zCsicMWpAA",
   "token_type": "example",
   "expires_in": 3600,
   "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
   "authorization_details": [
         "type": "",
         "actions": [
         "locations": [
         "instructedAmount": {
            "currency": "EUR",
            "amount": "123.50"
         "creditorName": "Merchant123",
         "creditorAccount": {
            "iban": "DE02100100109307118603"
         "remittanceInformationUnstructured": "Ref Number Merchant"

If a Connect2id server deployment needs to return additional parameters in the token response it can do so by creating an SPI plugin.

2. Custom token response composer SPI

The creation of custom token success and error responses is facilitated via the CustomTokenResponseComposer (SPI) from the Connect2id server SDK.

Implementations have access to

If there is no need to modify the token response the plugin can simply pass it through.

Since Connect2id server v9.3.

3. Sample RAR plugin

This is a sample RAR plugin that obtains the content of the authorization_details from the optional authorisation data set during consent.

Token error responses and responses which have no associated RAR details are simply returned unmodified.

import net.minidev.json.JSONObject;
import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.util.*;
import com.nimbusds.openid.connect.provider.spi.tokens.response.*;

public class RARCustomizer implements CustomTokenResponseComposer {

    public TokenResponse compose(final TokenResponse originalResponse,
                                 final TokenResponseContext context) {

        if (originalResponse instanceof TokenErrorResponse) {
            return originalResponse;

        JSONObject authzData = context.getAuthorizationData();

        if (authzData == null) {
            // No data / RAR
            return originalResponse;

        JSONObject rarDetails;
        try {
            rarDetails = JSONObjectUtils.getJSONObject(
        } catch (ParseException e) {
            throw new RuntimeException("Internal error: " + e.getMessage(), e);

        if (rarDetails == null) {
            // No RAR
            return originalResponse;

        AccessTokenResponse successResponse = originalResponse.toSuccessResponse();

        try {
            JSONObject tokensObject = successResponse.toJSONObject();
            tokensObject.put("authorization_details", rarDetails);
            return AccessTokenResponse.parse(tokensObject);
        } catch (ParseException e) {
            throw new RuntimeException("Internal error: " + e.getMessage(), e);

4. Support

If you need assistance, contact Connect2id support.