OAuth 2.0 token introspection endpoint

1. Inspecting identifier-based access tokens

OAuth 2.0 secured resource servers must check the access token of each client request before carrying on with the actual processing of the request. Access tokens issued by the Connect2id server can be inspected at this endpoint, as specified in RFC 7662. If the token is valid and still active (hasn't expired) the endpoint will return the underlying authorisation properties.

The token introspection endpoint is generally intended for identifier-based access tokens, which represent a secure key to an authorisation stored with the Connect2id server. Identifier-based tokens are paramount to applications where token and client revocation must have an immediate effect. Self-encoded (JWT) access tokens can also be checked at this endpoint, however their encoding makes them better suited for validation on the spot (by checking their signature).

Note: Tokens can also be inspected at the Connect2id specific authorisation store API.

2. The token introspection URL

The token introspection endpoint URL can be obtained from the server discovery endpoint:

https://[base-server-url]/token/introspect

3. Prerequisites

Requests to the introspection endpoint must be either authenticated with client credentials or authorised with a bearer access token.

To this end the resource server should be registered as a minimal OAuth 2.0 client for the client_credentials grant type (as a client acting on its own behalf) and a scope value that matches the URI of the introspection endpoint, e.g. https://c2id.com/token/introspect.

Example client registration request:

POST /clients HTTP/1.1
Host: c2id.com
Authorization: Bearer ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6
Content-Type: application/json

{ 
  "grant_types" : [ "client_credentials" ], 
  "scope"       : "https://c2id.com/token/introspect"
}

Example registration response with the assigned client credentials (client_id and client_secret):

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "client_id"                  : "izad7cqy34bg4",
  "client_id_issued_at"        : 1448356530,
  "client_secret"              : "1fu9sZE56ydjzGmovEHjIDgrdYDcT5gd-gqgXwhvmS0",
  "client_secret_expires_at"   : 0,
  "registration_client_uri"    : "https://c2id.com/clients/izad7cqy34bg4",
  "registration_access_token"  : "1NfgTP09qheYkNR7Pj6kCUVAp3gW-el0Ka9-U3Emu7Q.Kg",
  "grant_types"                : [ "client_credentials" ],
  "response_types"             : [ ],
  "token_endpoint_auth_method" : "client_secret_basic",
  "scope"                      : "https://c2id.com/token/introspect"
}

3.1 Client authentication

This is the simplest and recommended approach. The resource server authenticates itself to the token introspection endpoint with the registered method and credentials.

The example above implies client_secret_basic authentication. The resource server may register for another token_endpoint_auth_method, such as client_secret_jwt or private_key_jwt which are more secure and use a JWT assertion instead of HTTP basic auth.

Upon receiving a token introspection request the Connect2id server will validate the client credentials, and if they match a client that is registered for the expected scope (e.g. https://c2id.com/token/introspect) the request will get a go ahead.

3.2 Token authorisation

This approach uses a token to authorise the introspection request.

First, the resource server must first make a request to obtain an access token for the expected scope (represented by the introspection endpoint URI) using its registered client credentials grant.

POST /token HTTP/1.1
Host: c2id.com
Authorization: Basic aXphZDdjcXkzNGJnNDoxZnU5c1pFNTZ5ZGp6R21vdkVIaklEZ3JkWURjVDVnZC1ncWdYd2h2bVMw
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&scope=https%3A%2F%2Fc2id.com%2Ftoken%2Fintrospect

The Connect2id server returns an access token, in this example it is valid for 10 minutes:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "access_token" : "eyJhbGciOiJSUzI1NiIsImtpZCI6InMxIn0.eyJzY3AiOlsidG9rZW4ta...",
  "token_type"   : "Bearer",
  "expires_in"   : 600,
  "scope"        : "https://c2id.com/token/introspect"
}

The resource server can then pass this access token in the Authorization header of token introspection requests, until the token expires or is about to expire. The resource server can then repeat the previous step to obtain a new access token.

4. Web API overview

Resources
Representations Errors

4. Resources

4.1 /token/introspect

4.1.1 POST

Inspects an access token. Inspection of refresh tokens is not supported by the Connect2id server, although they may be submitted according to the RFC 7662 spec.

Clients must authenticate or submit a bearer token authorisation.

Header parameters:

Body with form parameters:

  • token The token to inspect.

  • [ token_type_hint ] Optional hint about the type of the submitted token; if omitted the server will use heuristics to determine the token type:

    • access_token -- the token is an access token

    • refresh_token -- the token is a refresh token (not supported)

Success:

Errors:

Example token introspection request using basic authentication:

POST /token/introspect HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

token=45ghiukldjahdnhzdauz

Example token introspection request using client secret JWT authentication:

POST /token/introspect HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded

token=45ghiukldjahdnhzdauz&
 client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
 client_assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6IjIyIn0.eyJpc3Mi...

Example token introspection request using bearer token authorisation:

POST /token/introspect HTTP/1.1
Host: c2id.com
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InMxIn0.eyJzY3AiOlsiaHR0...

token=45ghiukldjahdnhzdauz

The server will return a 200 status regardless of whether the submitted token was valid or not (required by the specification):

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "active"     : true,
  "scope"      : "https://example.com/accounts https://example.com/groups",
  "client_id"  : "izad7cqy34bg4",
  "token_type" : "Bearer",
  "exp"        : 1448367412,
  "sub"        : "izad7cqy34bg4",
  "iss"        : "https://c2id.com"
}

For an invalid token:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "active" : false
}

5. Representations

5.1 Token introspection response

The token introspection result is represented as a JSON object. The only required member according to RFC 7662 is active which indicates the token's validity.

If the token is valid the Connect2id server will include the available token details in the response.

If the token is invalid or has expired active will be set to false and no other details will be included.

  • active {true|false} If true the token is valid and active. If false the token is either invalid or has expired.

  • [ scope ] {string} The scope values for the token. The Connect2id server will always set this value.

  • [ client_id ] {string} The identifier of the OAuth 2.0 client that requested the token. The Connect2id server will always set this value.

  • [ username ] {string} Username of the resource owner who authorised the token.

  • [ token_type ] {string} Type of the token, set to Bearer. The Connect2id will always set this value.

  • [ exp ] {number} The token expiration time, as number of seconds since the Unix epoch (1970-01-01T0:0:0Z) as measured in UTC until the date/time. Has the same semantics as the JWT claim name. The Connect2id server will always set this value.

  • [ iat ] {number} The token issue time, as number of seconds since the Unix epoch (1970-01-01T0:0:0Z) as measured in UTC until the date/time. Has the same semantics as the JWT claim name.

  • [ nbf ] {number} The token use-not-before time, as number of seconds since the Unix epoch (1970-01-01T0:0:0Z) as measured in UTC until the date/time. Has the same semantics as the JWT claim name.

  • [ sub ] {string} The subject of the token. Typically the user identifier of the resource owner who authorised the token. Has the same semantics as the JWT claim name. The Connect2id server will always set this value.

  • [ aud ] {string array} Audience values for the token. Has the same semantics as the JWT claim name.

  • [ iss ] {string} The token issuer (the OpenID provider issuer identifier). Has the same semantics as the JWT claim name.

  • [ jti ] {string} Identifier for the token. Has the same semantics as the JWT claim name.

  • [ dat ] {object} Optional custom authorisation data.

Example introspection response for a valid token:

{
  "active"     : true,
  "scope"      : "https://example.com/accounts https://example.com/groups",
  "client_id"  : "izad7cqy34bg4",
  "token_type" : "Bearer",
  "exp"        : 1448367412,
  "sub"        : "izad7cqy34bg4",
  "iss"        : "https://c2id.com"
}

Example introspection response for an invalid or expired token:

{ 
  "active" : false
}

5. Errors

400 Bad Request

Invalid or malformed request.

Example:

HTTP/1.1 400 Bad Request

{
  "error"             : "invalid_request",
  "error_description" : "Invalid request: Missing required token parameter"
}

401 Unauthorized

The request was denied due to an invalid or missing client authentication / authorisation.

Example:

HTTP/1.1 401 Unauthorized

{
  "error"             : "invalid_client",
  "error_description" : "Client authentication failed: Missing client authentication / token"
}

403 Forbidden

The request was denied due to the client registration or authorisation token not having the required scope.

Example:

HTTP/1.1 403 Forbidden

{
  "error"             : "access_denied",
  "error_description" : "Client not registered for https://c2id.com/token/introspect scope"
}

500 Internal Server Error

An internal server error has occurred. Check the Connect2id server logs for details.

Example:

HTTP/1.1 500 Internal Server Error