Client authentication to /token through an incoming JSON Web Token

Security Access Manager OIDC Providers support client authentication to /token through an incoming JSON Web Token (JWT).

Some deployment scenarios, such as Open Banking, require the use of a signed assertion as a method to replace client_id and client_secret. To view the implementer requirements for client authentication, see https://www.openbanking.org.uk/read-write-apis/security-profile/id1-0-1/.

Security Access Manager OIDC Providers support client authentication to /token through an incoming JSON Web Token (JWT). Security Access Manager support of client assertions satisfies RFC 7523. See https://tools.ietf.org/html/rfc7523.

Note: Support for authentication to /token with a JWT is different from support for request JWTs that are presented to /authorize. For /authorize, see Passing parameters through JWT in a request to /authorize.

When an incoming client assertion is detected by the presence of the parameters client_assertion_type (of a valid value) and client_assertion, the OAuth delegate invokes a token exchange. This token exchange is to a well-known (predictable) set of issuer and appliesTo values.

The JWT must contain the following claims:

iss
The issuer of the JWT. This value must be that of the security entity that created this JWT. Its presence is validated, but explicit validation of the value must be completed in the STS chain.
sub
Subject Identifier. This value must be the client_id you want to authenticate.
aud
Intended audiences for the ID Token. It must be a value that represents this entity, such as the API Protection definition name.
exp
Expiration time on or after which the JWT is not accepted for processing.

The parameter nbf, if present, is validated. This parameter is the "not before" claim that identifies the time before which the JWT is not accepted for processing.

You can create a Secure Token Service (STS) chain with modules to handle client assertions through incoming JWTs during authentication. To configure an STS chain that is compatible with incoming client assertions, the chain must ensure:

  1. No token type is set.
  2. RequestType of Validate is accepted.

Examples of ISSUER and APPLIESTO fields that handle all presented client assertions are as follows:

ISSUER="REGEXP:(urn:ietf:params:oauth:client-assertion-type:jwt-bearer:.*)"
APPLIESTO=https://localhost/sps/oauth/oauth20
Note: In the example above, all clients match with this chain. (Note the .* value in the regexp for the Issuer.) If a particular chain is needed, then use the issuer:urn:ietf:params:oauth:client-assertion-type:jwt-bearer:myClient where myClient is the client_id of the interested client.
  • The issuer is a combination of the assertion type plus the client identifier.
  • The appliesto is the federation name. For Security Access Manager, the federation name is always:
    https://localhost/sps/oauth/oauth20

The client configured secret and jwks_uris are included in the request to the STS through WS-Trust claims. To view how the JWT module supports validation, see Validate mode.

After the JWT is validated, OAuth expects a Secure Token Service Universal User (STSUU) in return, as follows:

  • The sub claim is populated with the client_id of the incoming request.
  • The aud field is checked against the configured issuer identifier of the API definition.
    Note: The values of iss and aud must be validated. This validation can be done through the STS chain configuration, or in a map module in the STS chain, or in the pre-token mapping rule. Validation within the chain is easiest when the values of iss and aud are static.

All the claims in the JWT are mapped into the STSUU attribute list, with the type similar to urn:ibm:oauth20:client:assertion.

To implement this set of features, you must configure an STS chain with the following modules:

  • JWT module in Validate mode >
  • An optional JavaScript mapping rule >
  • STSUU module in Issue mode

Following is an example of code for retrieving the values:


var sub = stsuu.getAttributeContainer().getAttributeValueByName("sub");
var aud = stsuu.getAttributeContainer().getAttributeValueByName("aud");
var iss = stsuu.getAttributeContainer().getAttributeValueByName("iss");
IDMappingExtUtils.traceString("sub: " + sub + " aud: " + aud + " iss: " + iss);