Token Procedure Plugins

The Curity Security Token Server uses token procedures to issue tokens (see Issuing OAuth and OpenId Connect Tokens). These procedures can be defined as JavaScript scripts, described on Token procedures, or as SDK plugins, as documented in this section.

A token procedure plugin is an SDK plugin providing one or more procedures. Token procedures provided via plugins are specific to an endpoint (e.g. token endpoint) and to a flow on that endpoint (e.g. authorization code grant), as illustrated in the following table:

Table 34 token procedure types
Endpoint Flow Procedure Type
Authorization Endpoint Authorization Code AuthorizeCodeTokenProcedure
Authorization Endpoint Hybrid OpenIdAuthorizeEndpointHybridTokenProcedure
Authorization Endpoint Implicit AuthorizeImplicitTokenProcedure
Device Authorization Endpoint Device Authorization DeviceAuthorizationTokenProcedure
Introspection Endpoint Introspection IntrospectionTokenProcedure
Introspection Endpoint Introspection using JWT IntrospectionApplicationJwtTokenProcedure
Token Endpoint Assertion Token AssertionTokenProcedure
Token Endpoint Authorization Code AuthorizationCodeTokenProcedure
Token Endpoint CIBA BackchannelAuthenticationTokenProcedure
Token Endpoint Client Credentials ClientCredentialsTokenProcedure
Token Endpoint Device Code DeviceCodeTokenProcedure
Token Endpoint Refresh Token RefreshTokenProcedure
Token Endpoint Resource Owner Password Credential RopcTokenProcedure
Token Endpoint Token Exchange TokenExchangeTokenProcedure
Assisted Token Endpoint Assisted Token AssistedTokenProcedure
UserInfo Endpoint UserInfo OpenIdUserInfoTokenProcedure

A token plugin can provide zero or one procedure for each one of the above types.

Configuring and using Token Procedure Plugins

Token plugins are added globally on the processing configuration container, more specifically on the token procedure plugins list.

The following two figures illustrate listing and adding a token procedure plugin.

../_images/token-procedure-plugin-list.jpg

Fig. 159 Listing token procedure plugins.

../_images/token-procedure-plugin-add.jpg

Fig. 160 Adding a token procedure plugin.

After a token procedure plugin is configured globally then it can be used by an endpoint of a concrete token service profile, by setting the plugin identifier (e.g. example-procedure-plugin-1) on the endpoint configuration (e.g. authorization endpoint configuration).

The following figure illustrates using the procedure provided by the example-procedure-plugin-1 on the authorization endpoint and for the authorization code flow.

../_images/token-procedure-plugin-associate.jpg

Fig. 161 Using a procedure provided by a token procedure plugin on an endpoint.

Note that this association is only possible if the token procedure plugin contains internally a token procedure of the type required by the endpoint and flow being configured. Note also that it is not necessary to select which internal procedure to use from the plugin, since a token procedure plugin can contain at most one procedure of each type.

Developing Token Procedure Plugins

A token procedure plugin is an SDK plugin and the Curity Plugins SDK contains documentation with an overview on how the plugin system works. For reference information of the Java types, use Plugins SDK Javadocs.

A token procedure plugin is described by a descriptor class, implementing the TokenProcedurePluginDescriptor interface, and overriding a get method for each token procedure type that is supported by the plugin. For instance, a token procedure plugin providing a token procedure usable on the authorization endpoint for the authorization code flow, must:

  • Contain a class implementing the AuthorizeCodeTokenProcedure interface.
  • In the descriptor class, override the getOAuthAuthorizeEndpointCodeTokenProcedure method so that it returns the Class instance for the class implementing the AuthorizeCodeTokenProcedure interface.

A token procedure provided by a plugin is a class implementing one of the base interfaces (e.g.``AuthorizeCodeTokenProcedure``), containing a single run method, receiving a context and returning a ResponseModel. The returned response model is used by Curity Identity Server to build the endpoint response. The context, which has a different type per procedure type, provides data and services required to produce the endpoints response map, namely issuing tokens.

The following class exemplifies a token procedure for the authorization code flow of the token endpoint. Notice the use of default data and token issuers, provided by the context, to create the different tokens required for the response.

Listing 157 Example token procedure for the authorization code flow of the token endpoint, written using the Kotlin language.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class ExampleAuthorizationCodeTokenProcedure(
    private val config: ExampleTokenProcedurePluginConfiguration,
) : AuthorizationCodeTokenProcedure {

    override fun run(context: AuthorizationCodeTokenProcedurePluginContext) {
        try {
            val defaultDelegationData = context.defaultDelegationData
            val delegation = context.delegationIssuer.issue(defaultDelegationData)

            val defaultAccessTokenData = context.defaultAccessTokenData
            val accessToken = context.accessTokenIssuer.issue(defaultAccessTokenData, delegation)
                ?: throw TokenIssuerException("AccessToken must always be issued, but wasn't.")

            val refreshToken = context.refreshTokenIssuer.issue(context.defaultRefreshTokenData, delegation)

            val idToken = if (context is OpenIdConnectAuthorizationCodeTokenProcedurePluginContext) {
                var idTokenData = context.defaultIdTokenData
                if (idTokenData == null) {
                    null
                } else {
                    idTokenData = IdTokenAttributes.of(idTokenData.with(
                        Attribute.of(
                            "at_hash", context.idTokenIssuer.atHash(accessToken)
                        )
                    ))
                    context.idTokenIssuer.issue(idTokenData, delegation)
                }
            } else {
                null
            }

            val result = mutableMapOf<String, Any>(
                "access_token" to accessToken,
                "refresh_token" to refreshToken,
                "scope" to defaultAccessTokenData.scope,
                "token_type" to "bearer",
                "expires_in" to Duration.between(Instant.now(), defaultAccessTokenData.expires).seconds,
            )
            if (idToken != null) {
                result["id_token"] = idToken
            }
            if (context.accessTokenClaimNames != null) {
                result["claims"] = context.accessTokenClaimNames
            }

            return ResponseModel.mapResponseModel(result)
        } catch (ex: TokenIssuerException) {
            throw config.getExceptionFactory().internalServerException(ErrorCode.TOKEN_ISSUANCE_ERROR, ex.message)
        }
    }

The reference documentation for the TokenProcedure, present in the plugins SDK Javadocs <https://curity.io/docs/idsvr-java-plugin-sdk/latest>, contains information about all the available procedure types, as well as the context classes that they may receive.

Known limitations

Currently, token procedures provided by plugins:

  • Can only use default token issuers.