ISAM: Understanding OAuth introspection authorization
Many thanks to Serge Vereecke for collaborating with me on this article.
OAuth introspection is a fundamental of OAuth these days. It gives an standard way for a resource server (Such as WebSEAL in 9.0.7.0) to request validation of an access token from an authorization server. In ISAM 9.0.3.0 an RFC compliant introspection endpoint was added (RFC7662). However part of this solution was revisited in 9.0.7.0 to make the ISAM authorization server integrate with API gateways in a more friendly manner. The key change was to the options which ISAM makes available in configuring the client authorization requirements for introspection.
The goal of this article will be to explore what was in ISAM 9.0.3.0 to 9.0.6.0, and what changed in 9.0.7.0.
The OAuth introspection RFC indicates that the introspection endpoint must require some level of Authorization:
To prevent token scanning attacks, the endpoint MUST also require
some form of authorization to access this endpoint, such as client
authentication as described in OAuth 2.0 [RFC6749] or a separate
OAuth 2.0 access token such as the bearer token described in OAuth
2.0 Bearer Token Usage [RFC6750]. The methods of managing and
validating these authentication credentials are out of scope of this
specification.
In ISAM 9.0.3.0 there were three configurations available when configuring OAuth introspection.
-
Whether introspection was enabled
-
Whether non-confidential clients can introspect
-
Whether clients can introspect tokens issued to other clients
The third point here being key to enable an API gateway to validate tokens from any number of OAuth clients.
Enabling introspection
Introspection is enabled on a global-appliance level using an advanced configuration property. The configuration key is:
oauth20.introspectEndpointEnabled
Note: since 9.0.4.0 introspection has been enabled by default.
If introspection is attempted when the endpoint is disabled, the following error will occur:
HTTP/1.1 500 Internal Server Error
content-type: application/json
{"error_description": "The authorization server encountered an unexpected condition which prevented it from fulfilling the request.",
"error": "server_error"}
Non-Confidential client introspection
Non-Confidential clients are inherently non-trustworthy. So the default stance of ISAM is to deny introspection to clients which do not have a client-secret. This is achieved using the pre-token mapping rule.
At the start of the rule there is a line:
var only_allow_conf_client_introspect = true;
This line controls this block:
if((only_allow_conf_client_introspect && request_type == "introspect") || (request_type == "revoke" && only_allow_conf_client_revoke)) {
if(oauth_client != null) {
var client_id = oauth_client.getClientId();
if(!oauth_client.isConfidential()) {
// 401
OAuthMappingExtUtils.throwSTSAccessDeniedMessageException("Client Forbidden");
...
}
Which very simply checks if the client has been issued a secret, and if it hasn’t the request is denied.
Note: prior to 9050 this performed a client lookup with OauthMappingExtUtils.getClient(clientId), this is no longer needed and should be removed. The oauth_client variable is now always populated, and supports both static and dynamic clients.
Cross-client introspection
In some instances its necessary to let a client introspect all tokens issued by the authorization server. This needs to be done with careful consideration, as if these credentials are leaked then the authorization server may be vulnerable to token scanning attacks.
This capability was provided via the post-token mapping rule snippet, controlled with:
var must_client_own_token_introspect = true;
This snippet, when enabled, checked the client_id of the introspect response against the client_id used for authorization and if they didn’t match, would return an inactive token response.
Token introspection with API gateways
Some API gateways, such as IBM API Connect, use a different pattern. Rather than the gateway storing a single set of client-credentials, which are authorised to introspect all tokens, instead the gateway forwards the client-id of the caller along with the access_token to the introspection endpoint. The client-id of the caller is being used as the authorization material. Using this pattern requires that API clients send their client-id, in addition to an access_token, with every API request..
When applying this pattern to the ISAM introspection authorization model, this worked just fine for non-confidential clients if they were allowed to introspection but it provided no way forward for a confidential client to be introspected by the API gateway.
New in 9.0.7.0
What was added in 9.0.7.0 was a new configuration property “Require client secret for introspection”. This configuration option allows the API gateway pattern to be achieved with confidential clients too. This parameter was added to an OAuth client definitions:
This allows the given client to introspect their own tokens using just their client_id, which now allows a confidential client to have their tokens introspected using the API Connect client-id pattern. There are a few things to note here:
1. only_allow_conf_client_introspect is in the pre-token mapping rule, and will still apply to block non-confidential clients from performing introspection.
2. To ensure an appropriate security posture, when clients are allowed to introspect tokens without a client-secret the authorization server will always ensure the client is only introspecting their own tokens, regardless of the setting of must_client_own_token_introspect in the post-token rule.
This allows an API gateway to allow individual clients to present requests including their client Ids and for that client-id to be forwarded on as the authorization context to use in introspection requests. A key pattern in modern API authorization use-cases. So now administrators can decide the authorization approach they take to token introspection:
1. A set of client credentials capable of introspecting all tokens embedded into the gateway.
2. Clients only introspecting their own tokens via the gateway proxying their credentials.
It is notable that the two approaches are somewhat orthogonal, and if clients are enabled to introspect each others tokens and not required to provide a secret, then they will not be able to successfully introspect any tokens beyond their own.
The full authorization decision chain in a diagram