Access token encoding and introspection SPIs

1. Introduction

The Connect2id server can issue access tokens with two kinds of encodings:

  • Self-contained -- The authorisation is encoded in a JSON Web Token (JWT), which a resource server can validate locally by checking its digital signature.

  • Identifier-based -- A high-entropy key to an authorisation record in the Connect2id server database. The resource server validates the key and retrieves the associated data with a call to the introspection endpoint.

Deployments are in most cases fine with the provided access token encodings and introspection output provided by the Connect2id server. If some customisation is necessary the server exposes three helpful Java Service Provider Interfaces (SPI) for that:

A context parameter is passed with each call so that the cryptographic facilities (e.g. JWS signer) and the OpenID claims source of the Connect2id server can be accessed if needed.

The access token SPIs were introduced in Connect2id server v6.17.

2. Self-contained access token claims codec

This SPI determines how a token authorisation is converted to a JWT claims set and vice versa. You can use it to set an alternative claims encoding to the one provided by the Connect2id server.

The SPI is most likely to be needed when the resource servers expect a different name or format for some non-standard JWT claim, such as the claim to represent the token scope or the client to which the token was issued. In that case extend the provided BaseSelfContainedAccessTokenClaimsCodec class.

@Override
public JWTClaimsSet encode(final AccessTokenAuthorization tokenAuthz, final TokenEncoderContext context) {

    // Encode the claims for which we have standard (registered) names
    JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder(super.encode(tokenAuthz, context));

    // client_id
    if (tokenAuthz.getClientID() != null)
        builder.claim("client_id", tokenAuthz.getClientID().getValue());

    // scope
    if (tokenAuthz.getScope() != null)
        builder.claim("scope", tokenAuthz.getScope().toString());

    return builder.build();
}


@Override
public AccessTokenAuthorization decode(final JWTClaimsSet claimsSet, final TokenCodecContext context)
    throws TokenDecodeException {

    // Decode the claims for which we have standard (registered) claims
    MutableAccessTokenAuthorization authz = new MutableAccessTokenAuthorization(super.decode(claimsSet, context));

    String clientID = claimsSet.getStringClaim("client_id");

    if (clientID != null)
        authz.withClientID(new ClientID(clientID));

    String scope = claimsSet.getStringClaim("scope");

    if (scope != null && ! scope.trim().isEmpty())
        authz.withScope(Scope.parse(scope));

    return authz;
}

Note that the default JWT claims codec allows arbitrary custom parameters to be put in the top-level data ("dat") parameter; i.e. you don't need to create your own custom SPI implementation to include additional data in the JWT (unless the custom parameters must be top-level members of the JSON object).

FAQ:

  1. How can I verify that my codec was loaded?

    The Connect2id server logs the loaded codec class at startup under AS0511 at INFO level:

    MAIN - [AS0511] Loaded class com.nimbusds.authzstore.codecs.DefaultSelfContainedAccessTokenClaimsCodec
    

3. Identifier-access token codec

This SPI generates secure random identifiers for access tokens.

The default implementation provided by the Connect2id server produces an 128-bit identifier for each token. The identifier has an extra SHA-256 HMAC protection (truncated to 128 bits) appended to it. During introspection the HMAC enables the codec to detect tokens that aren't issued by the Connect2id server, causing a suitable warning to get logged and preventing an unneeded database lookup.

The SPI enables plug in of a custom codec. For example, a codec where the identifier is encapsulated in a signed JWT along with the issuer URL, expiration time and client certificate confirmation, to provide resource servers in multi-tenant deployments with a hint where to introspect the token, and also allow part of the token validation to happen before the introspection call.

{
  "iss" : "https://t1.c2id.com",
  "jti" : "Hoofao7Ve1ohg4chahBee9Xee1ahvaed",
  "exp" : 1519660677,
  "cnf" : { "x5t#S256" : "Shoohie2Pee1ubi9aehai3leg0woidet" }
}

Check out this example for an alternative "hybrid" codec.

FAQ:

  1. How can I verify that my codec was loaded?

    The Connect2id server logs the loaded codec class at startup under AS0510 at INFO level:

    MAIN - [AS0510] Loaded class com.nimbusds.openid.connect.provider.spi.tokens.HybridIdentifierAccessTokenCodec
    
  2. The Connect2id server issued a JWT-encoded access token?

    The default encoding of issued access tokens by the Connect2id server is self-contained (JWT). To ask for an identifier-based token to be issued set the access_token.encoding parameter in your authorisation session handler. The password grant, client credentials and other grant handlers also assume self-contained access tokens by default.

4. Token introspection response composer

Resource servers check identifier-based access tokens at the standard token introspection endpoint.

The TokenIntrospectionResponseComposer SPI allows the default response format to be overridden.

One use of that is to respond differently to different resource servers making the same introspection request. For instance, an authorisation server may limit which scopes from a given token are returned for each resource server, to prevent it from learning more about the larger network than is necessary for its operation.

A sample implementation of that can be found in the Connect2id server SDK test suite. Requires the resource server to be registered as a client to the Connect2id server (which is already a prerequisite to inspect tokens), where in the possible scope values that it may see are listed in the "scope" registration field.

FAQ:

  1. How can I verify that my response composer was loaded?

    The Connect2id server logs the loaded class at startup under OP6530 at INFO level:

    MAIN - [OP6530] Loaded class com.nimbusds.openid.connect.provider.spi.tokens.introspection.TokenScopeShaper
    

5. Support

If you need assistance, contact Connect2id support.