<!--
SPDX-FileCopyrightText: 2025 Steven van der Vegt

SPDX-License-Identifier: CC-BY-SA-4.0
-->

### Scope

The transaction Introspect Access Token allows a resource server (Custodian) to validate and obtain metadata about an access token issued by an authorization server (Verifier).

The introspection returns the active state of the token along with additional identity claims associated with the token. This information can be used by the resource server dow stream during the authorization decision.

The introspection transaction is added so the access token format can be opaque to the resource server. This allows the authorization server to use any token format, including self-contained tokens such as JWTs, without requiring the resource server to understand the token format.

In case the access token is a self-contained token such as a JWT, the resource server can validate the token locally without needing to call the introspection endpoint. However, the resource server needs to be able to validate the token signature and parse the token claims which adds complexity and duplicates logic that is already present in the authorization server.

### Actor Roles

| Actor     | Role                                                                                            |
| --------- | ----------------------------------------------------------------------------------------------- |
| Custodian | Validates the access token and retrieves metadata about the token from the authorization server |
| Verifier  | Provides an introspection endpoint to validate access tokens and return associated metadata     |

### Referenced standards

- [OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
- [OAuth 2.0 Token Introspection](https://datatracker.ietf.org/doc/html/rfc7662)
- [OAuth 2.0 Demonstration of Proof-of-Possession (DPoP)](https://datatracker.ietf.org/doc/html/rfc9449)

### Messages

1. Introspect Access Token Request
2. Introspect Access Token Response

<div>
{% include GFI-006.svg %}
</div>

#### Introspect Access Token Request

##### Trigger events

- A resource server (Custodian) needs to validate an access token presented by a client (Holder) and obtain metadata about the token and identity claims of the holder.

##### Message semantics

The resource server initiates an introspect access token request using a HTTP POST request to the authorization server's introspection endpoint. The request includes the access token to be introspected.

##### Example

Below is a non-normative example of an Introspect Access Token Request:

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

token=Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU
```

#### Introspect Access Token Response

##### Trigger events

- The authorization server responds to the introspect access token request with the active state of the token and associated metadata.

##### Message semantics

The authorization server responds with a HTTP 200 OK response containing a JSON object in the body of the response. The JSON object includes an `active` boolean field indicating whether the token is valid.

The `iss` must be the decentralized identifier (DID) of the authorization server.
The `aud` must be the decentralized identifier (DID) of the custodian.

For a DPoP bound access token, the response also includes a `cnf` claim containing the public key information that can be used to verify the DPoP proof presented by the client as defined in [Section 6.2 of RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449#section-6.2).

The response may also include the identity claims associated with the token in the `assertions` and `client_assertions` properties. Claims are grouped by subject and each claim has an array of objects with the metadata of the claim, such as the issuer, validity period and the actual claim value.

##### Example

Below is a non-normative example of an Introspect Access Token Response:

```
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
  "active": true,
  "scope": "read write",
  "token_type": "DPoP",
  "exp": 1419356238,
  "iat": 1419350238,
  "nbf": 1419350238,
  "aud": "did:web:custodian.example.com",
  "iss": "did:web:verifier.example.com",
  "jti": "123e4567-e89b-12d3-a456-426614174000",
  "cnf": {
    "jkt": "0ZcOCORZNYy-DWpqq30jZyJGHTN0d2HglBV3uiguA4I"
  },
  "assertions": {
    "did:web:example.com:users:john": {
      "name": [{
        "value": "John Doe",
        "iss": "https://issuer.example.com",
        "iat": 1618884473,
        "exp": 1672531199
      }],
      "email": [{
        "value": "john@example.com",
        "iss": "https://issuer.example.com",
        "iat": 1618884473,
        "exp": 1672531199
      },{
        "value": "john.doe@other.example.com",
        "iss": "https://other-issuer.example.com",
        "iat": 1618884473,
        "exp": 1672531199
      }]
    },
    "did:web:org.example.com": {
      "identifier": [{
        "value": {
            "type": "Organization",
            "name": "Example Org",
            "registrationNumber": "123456789"
        },
        "iss": "https://issuer.example.com",
        "iat": 1618884473,
        "exp": 1672531199
      }]
    }
  },
  "client_assertions": {
    "did:web:example.com:apps:myapp": {
      "app_id": [{
         "value": "myapp",
         "iss": "https://auth.example.com",
         "iat": 1618884473,
         "exp": 1672531199
      }],
      "certification": [{
        "value": "UseCase1,UseCase2",
        "iss": "https://auth.example.com",
        "iat": 1618884473,
        "exp": 1672531199
      }]
    }
  }
}
```

##### Expected actions

###### Response Handling

**Case 1**: The access token is valid.
`HTTP 200` (OK) is returned as the HTTP status code.
The response body contains a JSON object with the `active` field set to `true` and additional metadata about the token and identity claims.

**Case 2**: The access token is invalid or expired.
`HTTP 200` (OK) is returned as the HTTP status code.
The response body contains a JSON object with the `active` field set to `false`. Other
fields may be omitted or set to `null`.

**Case 3**: The introspection request is malformed or missing required parameters.
`HTTP 400` (Bad Request) is returned as the HTTP status code.
The response body contains an error message indicating the issue with the request.

###### DPoP Proof Validation

The authorization server does not check the validity of the DPoP proof. The resource server must validate the DPoP proof separately by checking the `cnf.jkt` claim in the introspection response against the DPoP proof presented by the client. This claim contains the JWK thumbprint of the public key used to sign the DPoP proof. The resource server must ensure that the `jkt` value matches the thumbprint of the public key in the DPoP proof to confirm that the client possesses the private key corresponding to the public key.
