---
title: Caching PingAM access tokens
description: This section builds on the example in Validating PingAM access tokens with introspection to cache and then revoke access tokens.
component: pinggateway
version: 2026
page_id: pinggateway:gateway-guide:oauth2-rs-cacheatr
canonical_url: https://docs.pingidentity.com/pinggateway/2026/gateway-guide/oauth2-rs-cacheatr.html
revdate: 2025-04-01T17:53:34Z
---

# Caching PingAM access tokens

This section builds on the example in [Validating PingAM access tokens with introspection](oauth2-rs-introspect.html) to cache and then revoke access tokens.

When the access token **is not** cached, PingGateway calls AM to validate the access token. When the access token **is** cached, PingGateway doesn't validate the access token with AM.

When an access token is revoked on AM, the CacheAccessTokenResolver can delete the token from the cache when both of the following conditions are true:

* The `notification` property of AmService is enabled.

* The delegate AccessTokenResolver provides the token metadata required to update the cache.

When a refresh\_token is revoked on AM, all associated access tokens are automatically and immediately revoked.

Before you start, set up and test the example in [Validating PingAM access tokens with introspection](oauth2-rs-introspect.html).

1. Add the following route to PingGateway:

   * Linux

     `$HOME/.openig/config/routes/rs-introspect-cache.json`

   * Windows

     `%appdata%\OpenIG\config\routes\rs-introspect-cache.json`

   ```json
   {
     "name": "rs-introspect-cache",
     "condition": "${find(request.uri.path, '^/rs-introspect-cache$')}",
     "heap": [
       {
         "name": "SystemAndEnvSecretStore-1",
         "type": "SystemAndEnvSecretStore"
       },
       {
         "name": "AmService-1",
         "type": "AmService",
         "config": {
           "url": "http://am.example.com:8088/openam",
           "realm": "/",
           "agent" : {
             "username" : "ig_agent",
             "passwordSecretId" : "agent.secret.id"
           },
           "secretsProvider": "SystemAndEnvSecretStore-1"
         }
       }
     ],
     "handler": {
       "type": "Chain",
       "config": {
         "filters": [
           {
             "name": "OAuth2ResourceServerFilter-1",
             "type": "OAuth2ResourceServerFilter",
             "config": {
               "scopes": [
                 "mail",
                 "employeenumber"
               ],
               "requireHttps": false,
               "accessTokenResolver": {
                 "name": "CacheAccessTokenResolver-1",
                 "type": "CacheAccessTokenResolver",
                 "config": {
                   "enabled": true,
                   "defaultTimeout ": "1 hour",
                   "maximumTimeToCache": "1 day",
                   "amService":"AmService-1",
                   "delegate": {
                     "name": "TokenIntrospectionAccessTokenResolver-1",
                     "type": "TokenIntrospectionAccessTokenResolver",
                     "config": {
                       "amService": "AmService-1",
                       "providerHandler": {
                         "type": "Chain",
                         "config": {
                           "filters": [
                             {
                               "type": "HttpBasicAuthenticationClientFilter",
                               "config": {
                                 "username": "ig_agent",
                                 "passwordSecretId": "agent.secret.id",
                                 "secretsProvider": "SystemAndEnvSecretStore-1"
                               }
                             }
                           ],
                           "handler": {
                             "type": "Delegate",
                             "capture": "all",
                             "config": {
                               "delegate": "ForgeRockClientHandler"
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         ],
         "handler": {
           "type": "StaticResponseHandler",
           "config": {
             "status": 200,
             "headers": {
               "Content-Type": [ "text/html; charset=UTF-8" ]
             },
             "entity": "<html><body><h2>Decoded access_token: ${contexts.oauth2.accessToken.info}</h2></body></html>"
           }
         }
       }
     }
   }
   ```

   Source: [rs-introspect-cache.json](../_attachments/config/routes/rs-introspect-cache.json)

   Notice the following features of the route compared to `rs-introspect.json`, in [Validating PingAM access tokens with introspection](oauth2-rs-introspect.html):

   * The OAuth2ResourceServerFilter uses a CacheAccessTokenResolver to cache the access token, and then delegate token resolution to the TokenIntrospectionAccessTokenResolver.

   * The `amService` property in CacheAccessTokenResolver enables WebSocket notifications from AM, for events such as token revocation.

   * The TokenIntrospectionAccessTokenResolver uses a ForgeRockClientHandler and a capture decorator to capture PingGateway's interactions with AM.

2. Test token caching:

   1. In a terminal window, use a `curl` command similar to the following to retrieve an access token:

      ```console
      $ mytoken=$(curl -s \
      --user "client-application:password" \
      --data "grant_type=password&username=demo&password=Ch4ng31t&scope=mail%20employeenumber" \
      http://am.example.com:8088/openam/oauth2/access_token | jq -r ".access_token")
      ```

   2. Access the route, using the access token returned in the previous step:

      ```console
      $ curl -v \
      --cacert /path/to/secrets/ig.example.com-certificate.pem \
      --header "Authorization: Bearer ${mytoken}" \
      https://ig.example.com:8443/rs-introspect-cache
      ```

      Output

      ```
      {
       active = true,
       scope = employeenumber mail,
       client_id = client-application,
       user_id = {amDemoUn},
       token_type = Bearer,
       exp = 158...907,
       ...
      }
      ```

   3. In the route log, note that PingGateway calls AM to introspect the access token:

      ```
      POST http://am.example.com:8088/openam/oauth2/realms/root/introspect HTTP/1.1
      ```

   4. Access the route again. In the route log note that this time PingGateway doesn't call AM, because the token is cached.

   5. Disable the cache and repeat the previous steps to cause PingGateway to call AM to validate the access token for each request.

3. Test token revocation:

   1. In a terminal window, use a `curl` command similar to the following to revoke the access token obtained in the previous step:

      ```console
      $ curl --request POST \
      --data "token=${mytoken}" \
      --data "client_id=client-application" \
      --data "client_secret=password" \
      "http://am.example.com:8088/openam/oauth2/realms/root/token/revoke"
      ```

   2. Access the route using the access token and and note that the request isn't authorized because the token is revoked:

      ```console
      $ curl -v \
      --cacert /path/to/secrets/ig.example.com-certificate.pem \
      --header "Authorization: Bearer ${mytoken}" \
      https://ig.example.com:8443/rs-introspect-cache
      ```

      Output

      ```
      ...
      HTTP/1.1 401 Unauthorized
      ```
