Custom Token Issuer

Custom Token Issuer

tutorials

The Curity Identity Server issues opaque access and refresh tokens by default, whereas ID tokens are always JWTs. The default token issuers can, to some extent, be configured. This mainly applies to the default JWT issuer. Here, things like the algorithm, signing key, clock skew, and other settings can be changed with simple configuration settings.

When a use case requires a more custom approach to issuing tokens, it is possible to configure a custom token issuer and modify the token procedure to issue tokens differently. A typical scenario is that some OAuth clients need an access token as a JWT, but others need an opaque token. Although it is possible to configure a token service in the Curity Identity Server to always issue JWTs as access tokens, this would affect all clients configured in that token service, requiring multiple token services and adding overhead to configuration management. Instead, it is possible to leverage a client property to invoke a specific token issuer for only that client.

Creating a Custom Issuer

To create a custom token issuer, navigate to Token Service Token Issuers within an OAuth profile, scroll down to the bottom and click New Token Issuer. Give it a name, issuer type, and purpose type, and then click Create.

Configure the rest of the custom issuer according to your requirements. In the below example, the custom token issuer will issue access tokens as JWTs.

Click Close and Commit the changes.

Configure Issuer for a Client

Client properties are key-value pairs that can be configured for a client and used in, for example, a token procedure. To add a client property, edit the client and navigate to Client Application Settings Advanced Properties. Click Add property and enter a key/value pair. The example below sets the value defaultJwt for the key at_issuer.

Client properties

A different client can be configured with a property at_issuer with the value customJwtIssuer as in the previous example screenshot.

Token Procedure

The token procedure for a given OAuth flow can be modified to invoke different token issuers from the default. Navigate to Token Service Endpoints, find the oauth-token endpoint and expand the Flows. Select the drop-down for the flow to modify (Authorization Code for example) and select New Procedure. Give it a name and click Save. A pop-up will appear that shows the code for the default issuer for the selected flow.

Endpoint flows

This example uses the Code Flow and the code that issues a token is as follows:

var issuedAccessToken =  context.accessTokenIssuer.issue(accessTokenData, issuedDelegation)

This is where modifications can be made to invoke a different issuer. The default JWT issuer (instead of an opaque issuer) can be called by simply modifying the code:

var issuedAccessToken = context.getDefaultAccessTokenJwtIssuer().issue(accessTokenData, issuedDelegation);

A custom issuer can also be called by referencing the name of the issuer.

var issuedAccessToken = context.getAccessTokenIssuer('customJwtIssuer').issue(accessTokenData, issuedDelegation);

Changing how a token is issued in this way is still not very flexible. It applies the same token issuer for the Code Flow regardless of the client. A helper function can be added to make this a bit more flexible.

The context.client object contains the configuration for a client, and context.client.properties represents the list of properties defined for the client. This can be used to determine what token issuer to use for what client.

function issueAccessToken(context, accessTokenData, issuedDelegation)
{
    var issuerType = context.client.properties['at_issuer'];
    var issuedToken;

    if(issuerType === undefined || issuerType === null || issuerType === 'default')
    {
        issuedToken = context.accessTokenIssuer.issue(accessTokenData, issuedDelegation);    }
    else if(issuerType === 'defaultJwt')
    {
        issuedToken = context.getDefaultAccessTokenJwtIssuer().issue(accessTokenData, issuedDelegation);    }
    else
    {
        issuedToken = context.getAccessTokenIssuer(issuerType).issue(accessTokenData, issuedDelegation);    }

    return issuedToken;
}

The first option is using the default method in the Curity Identity Server to issue tokens.

The second option uses the default JWT issuer. This will be used if the client property at_issuer has the value defaultJwt. This is a common scenario and doesn’t really involve a custom issuer. However, it does use a customized token procedure so that the access token is used as a JWT.

The third option covers all other cases and will invoke the token issuer that is specifically defined in the at_issuer client property. Earlier, the issuer created the example custom token customJwtIssuer. This would be called if that was defined as a property on the client.

With the helper function in place, the token procedure still needs to call the helper function.

This line:

var issuedAccessToken =  context.accessTokenIssuer.issue(accessTokenData, issuedDelegation)

Is replaced with:

var issuedAccessToken =  issueAccessToken(context, accessTokenData, issuedDelegation)

Conclusion

Key-value pair properties can be defined for OAuth clients and leveraged in token procedures. This allows customization where different token issuers can be invoked for different clients, including custom token issuers. The example outlined in this article demonstrates a flexible way of modifying the default token procedure for the Code Flow. This way, it can pick up the client property and invoke different token issuers depending on the configuration for the client used.

This approach is also outlined in the Using Custom Token Issuers in the Curity Identity Server recording.

Appendix A: Full Code Example (Code Flow)

Keep up with our latest articles and how-tos RSS feeds.