Issuing OAuth and OpenId Connect Tokens

All tokens in the Curity Security Token Server are issued using token procedures. These are executed after validation has been performed and are responsible for both issuing the tokens, and assembling the data that should be used as response to the client.

This gives the administrator enormous flexibility in what tokens can be issued and which data should be added to these.

../../_images/script-token-gen-example.png

Fig. 140 Processing of token request

The Curity Security Token Server supports three types of tokens, each with different characteristics regarding the token string returned to the client and the associated data:

  • JSON Web Token (JWT) - The token string is a JWT which includes all the token data.
  • Opaque - The token string is an opaque reference to the actual token data, similar to an UUID. The associated token data is obtained via introspection.
  • Wrapped opaque - The token string is a JWT whose contents do not expose the token data directly, except for a few metadata fields (e.g. expiration time). The associated token data is obtained via introspection.

The process of issuing tokens uses the concept of Token Issuers - used by token procedures - which take the token data as input and return an artifact string. Each issuer handles one of the aforementioned token types for a given purpose (e.g. access token, ID token). The Curity Security Token Server includes default token issuers for the different purposes and custom issuers may also be defined.

Default Token Issuers

By default Curity issues opaque tokens whenever the token format is not pre-defined (e.g. ID tokens are always JWT). The data associated with opaque tokens is persisted, so a data source that supports token storage must be configured using the default-data-source setting.

There are some configuration options that allow tweaking the behavior of the default token issuers, namely:

  • jwt-issuer-settings - Settings for the default JWT token issuer, such as which signing key to use.
  • access-token-as-jwt - Issue access tokens as JWT instead of opaque tokens.
  • use-wrapped-opaque-tokens - Issue tokens as wrapped opaque tokens instead of opaque tokens (when applicable).

The following is an example of the configuration for default token issuers using the options mentioned above.

Listing 153 Configuring default token issuers
<default-token-issuer>
    <jwt-issuer-settings>
        <signing-key-id>default-signing-key</signing-key-id>
        <verification-keystore-id>default-signature-verification-key</verification-keystore-id>
        <algorithm>RS256</algorithm>
    </jwt-issuer-settings>
    <access-token-as-jwt/>
    <default-data-source>DefaultHSQLDB</default-data-source>
</default-token-issuer>

For details on how to use the default issuers see Token procedures.

Custom Token Issuers

Custom token issuers are named issuers that are accessible by their name from token procedures. By defining a custom issuer, it is possible to issue some tokens with specific settings, while keeping the default settings in place for other tokens.

When configuring a custom issuer, its id, token type and token purpose must be defined. Other settings vary with the selected token type. For example, opaque tokens require a token data source.

The following is an example of the configuration for two custom issuers, one for wrapped opaque access tokens and another for opaque nonce tokens.

Listing 154 Configuring custom token issuers
<custom-token-issuer>
    <id>access-token-issuer</id>
    <issuer-type>wrapped-opaque</issuer-type>
    <purpose-type>access_token</purpose-type>
    <data-sources>
        <tokens-data-source-id>DefaultHSQLDB</tokens-data-source-id>
    </data-sources>
    <jwt>
        <signing-key-id>default-signing-key</signing-key-id>
        <verification-keystore-id>default-signature-verification-key</verification-keystore-id>
    </jwt>
</custom-token-issuer>
<custom-token-issuer>
    <id>nonce-issuer</id>
    <issuer-type>opaque</issuer-type>
    <purpose-type>nonce</purpose-type>
    <data-sources>
        <tokens-data-source-id>DefaultHSQLDB</tokens-data-source-id>
    </data-sources>
</custom-token-issuer>

The supported combinations of issuer type and purpose are identified below:

Issuer type Access token Refresh token ID token Nonce Generic Userinfo
JWT Yes No Yes No Yes Yes
Opaque Yes Yes No Yes No No
Wrapped opaque Yes Yes No Yes No No

More on Wrapped Opaque Tokens

The data associated with wrapped opaque tokens is twofold: data that goes into the JWT returned as the token string (the wrapper) and the main token data, which is obtained via introspection. Each part can be configured separately via claim mappers. Specifically, the data that goes into the wrapper JWT is defined by the wrapper-token claim sink, which is used whenever a wrapped opaque token is issued, regardless of its purpose.

Wrapped opaque tokens are useful in scenarios where the token consumer (e.g. client, resource server, infrastructure components) may need to process part of the token data before actually using/introspecting it. The wrapper JWT may contain non-sensitive claims to help the consumer in that case. An example of such scenarios is described in the HEART Profile for OAuth 2.0, where compliant resource servers may accept tokens from different authorization servers and need to inspect the token’s issuer in order to decide which introspection service to use.

Encrypted ID Tokens

The Curity Identity Server supports issuing encrypted ID tokens. As required by OpenID Connect, if an ID token is encrypted, it must be signed then encrypted, with the result being a nested JWT as defined by the JSON Web Token (JWT) specification. This means that an encrypted ID token encompasses two parts:

  1. An inner JWT, signed using JSON Web Signature (JWS). This token is issued by any of the ID token issuers described in the previous sections.
  2. An outer JSON Web Encryption (JWE) structure whose payload is the compact serialization of the previous JWT. This JWE is encrypted for a specific recipient, i.e. the client that started the authorization flow.

It is possible to configure the Curity Security Token Server so that encrypted ID tokens are enabled and, optionally, required. This can be done at different scopes:

  • Profile - see id-token-encryption on the OpenID Connect configuration settings.

    Enable encrypted ID tokens as a whole and define the allowed Key Management and Content Encryption algorithms for JWE.

  • Configured clients - see id-token-encryption on the configured client settings.

    Enable encrypted ID tokens for specific clients by defining the encryption key and the Key Management and Content Encryption algorithms to use.

  • Non-templatized dynamic clients - see require-id-token-encryption on the non-templatized dynamic clients configuration settings.

    Require that dynamic clients are registered with ID token encryption settings. Note that these clients can use encrypted ID tokens even if not required by the configuration, as long as encrypted ID tokens are enabled in the profile.

    Dynamic clients can define which Key Management and Content Encryption algorithms are used via the id_token_encrypted_response_alg and id_token_encrypted_response_enc client metadata values, respectively, as long as these are allowed by the profile. The encryption key is obtained from the JSON Web Key Set (JWKS) supplied on registration.

When possible, the issued JWE will include the Key ID (kid) and the X.509 Certificate SHA-256 Thumbprint (x5t#S256) header parameters. This may be particularly helpful for dynamic clients that have multiple encryption keys in their JWKS. If multiple keys are applicable when issuing an encrypted ID token, the ones that include the Key ID (kid) header parameter are preferred and then the first key in the JWKS order is used.

The supported Key Management and Content Encryption algorithms are exposed in the metadata endpoint when encrypted ID tokens are enabled.