---
title: PingGateway scripts
description: PingGateway uses Groovy for scripting. Learn more in the Groovy Language Documentation.
component: pinggateway
version: 2026
page_id: pinggateway:reference:Scripts
canonical_url: https://docs.pingidentity.com/pinggateway/2026/reference/Scripts.html
revdate: 2026-01-20T12:00:00Z
section_ids:
  Scripts-usage: Usage
  Scripts-properties: Properties
  Scripts-availableob: Available objects
  Scripts-impclass: Imported classes
  examples: Examples
  accessing_secrets: Accessing secrets
  Scripts-moreinfo: More information
---

# PingGateway scripts

PingGateway uses Groovy for scripting. Learn more in the [Groovy Language Documentation](https://docs.groovy-lang.org/docs/groovy-4.0.28/html/documentation/).

Groovy scripts used in the PingGateway configuration are restricted to the UTF-8 character set.

Use Groovy scripts with the following object types:

* [ScriptableFilter](ScriptableFilter.html) to customize the flow of requests and responses.

* [ScriptableHandler](ScriptableHandler.html) to customize response creation.

* [ScriptableThrottlingPolicy](ScriptableThrottlingPolicy.html) to customize throttling rates.

* [ScriptableAccessTokenResolver](ScriptableAccessTokenResolver.html) to customize resolution and validation of OAuth 2.0 access tokens.

* `ScriptableResourceAccess` in [OAuth2ResourceServerFilter](OAuth2ResourceServerFilter.html) to customize the list of OAuth 2.0 scopes required in an OAuth 2.0 access token.

* [ScriptableIdentityAssertionPlugin](ScriptableIdentityAssertionPlugin.html) with an [IdentityAssertionHandler](IdentityAssertionHandler.html) for local processing.

When PingGateway accesses a script, it compiles and then caches the script. PingGateway uses the cached version until the script is changed.

After you update a script used in a route, wait at least one second before processing a request. The Groovy interpreter needs time to detect and take the update into account.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | When writing scripts or Java extensions that use the Promise API, avoid the blocking methods `get()`, `getOrThrow()`, and `getOrThrowUninterruptibly()`. A promise represents the result of an asynchronous operation; therefore, using a blocking method to wait for the result can cause deadlocks and/or race issues.Instead, consider using `then()` methods, such as `thenOnResult()`, `thenAsync()`, or `thenCatch()`, which allow execution blocks to be executed when the response is available.- Blocking code example```none
def response = next.handle(ctx, req).get() // Blocking method 'get' used
response.headers['new']="new header value"
return response
```- Non-blocking code example```none
return next.handle(ctx, req)
            //Process result when it is available
           .thenOnResult { response ->
             response.headers['new']="new header value"
           }
``` |

## Usage

```json
{
  "name": string,
  "type": scriptable object type,
  "config": {
    "type": string,
    "file": configuration expression<string>,  // Use either "file"
    "source": [ string, ... ],                 // or "source", but not both.
    "args": map or configuration expression<map>,
    "clientHandler": Handler reference
  }
}
```

## Properties

* `"type"`: *[string](preface.html#definition-string), required*

  The Internet media type (formerly MIME type) of the script, "application/x-groovy" for Groovy

* `"file"`: *configuration expression<[string](preface.html#definition-string)>, required if `source` isn't used*

  Path to the file containing the script; mutually exclusive with `source`. Specify `file` as follows:

  * For Groovy files from default packages

    * Place Groovy files in the base script directory, `$HOME/.openig/scripts/groovy` (on Windows, `%appdata%\OpenIG\scripts\groovy`). For example, place `myScript.groovy` from the default package in `$HOME/.openig/scripts/groovy`.

    * Specify `file` with the filename of the Groovy file. For the previous example, specify:

      ```json
      "config": {
        "type": "application/x-groovy",
        "file": "myScript.groovy"
      }
      ```

  * For Groovy files from non-default packages

    * Place Groovy files in a subdirectory of the base script directory that corresponds to the package name. For example, place `myScript.groovy` from the package `com.example.groovy` in `$HOME/.openig/scripts/groovy/com/example/groovy`.

    * Specify `file` with the relative path from the base script directory **and** the filename. For the previous example, specify:

      ```json
      "config": {
        "type": "application/x-groovy",
        "file": "com/example/groovy/myScript.groovy"
      }
      ```

  |   |                                                                                                                                                                                                                                                                                                                                                                                   |
  | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | PingGateway runs scripts from an absolute path, or from a path relative to the base script directory. Routes that refer to scripts otherwise, such as through a URL, fail to deploy.Do one of the following to prevent errors:* Move scripts to the base script directory or the correct subdirectory of the base script directory.

  * Refer to scripts through an absolute path. |

- `"source"`: *array of <[strings](preface.html#definition-string)>, required if `file` is not used*

  The script as one or more strings; mutually exclusive with `file`.

  The following example shows the source of a script as an array of strings:

  ```json
  "source": [
      "Response response = new Response(Status.OK)",
      "response.entity = 'foo'",
      "return response"
  ]
  ```

- `"args"`: *[map](preface.html#definition-map) or configuration expression\<map>, optional*

  A map of one or more data pairs with the format `Map<String, String>`, where:

  * The key is the name of a configuration parameter in a script

  * The value is a string to use in the script, or a configuration expression that evaluates to the string

  The following formats are allowed:

  ```json
  {
    "args": {
      "string": "configuration expression<string>",
      ...
    }
  }
  ```

  ```json
  {
    "args": "configuration expression<map>"
  }
  ```

  In the following example, the property is a map whose values are scalars, arrays, and objects:

  ```json
  {
    "args": {
      "title": "Coffee time",
      "status": 418,
      "reason": [
        "Not Acceptable",
        "I'm a teapot",
        "Acceptable"
      ],
      "names": {
        "1": "koffie",
        "2": "kafe",
        "3": "cafe",
        "4": "kafo"
      }
    }
  }
  ```

  * A script can access the `args` parameters in the same way as other global objects. The following example sets the response status to `I'm a teapot`:

    ```groovy
    response.status = Status.valueOf(418, reason[1])
    ```

    For information about the 418 status coderefer to [RFC 7168: 418 I'm a Teapot](https://www.rfc-editor.org/rfc/rfc7168#section-2.3.3).

  * The following example configures arguments as strings and numbers for a ScriptableThrottlingPolicy:

    ```json
    "args": {
      "status": "gold",
      "rate": 6,
      "duration": "10 seconds"
    }
    ```

    The following lines set the throttling rate to 6 requests each 10 seconds when the response status is `gold`:

    ```groovy
    if (attributes.rate.status == status) {
      return new ThrottlingRate(rate, duration)
    }
    ```

  * The following example configures arguments that reference a SampleFilter defined in the heap:

    ```json
    {
      "heap": [
        {
          "name": "SampleFilter",
          "type": "SampleFilter",
          "config": {
            "name": "X-Greeting",
            "value": "Hello world"
          }
        }
      ]
    }
    ```

    In the following example, the property is a map whose value is an expression to pass SampleFilter to the script:

    ```json
    {
      "args": {
        "filter": "${heap['SampleFilter']}"
      }
    }
    ```

    The script can then reference SampleFilter as `filter`.

- `"clientHandler"`: *ClientHandler [reference](preface.html#definition-reference), optional*

  A [Handler](Handlers.html) for making outbound HTTP requests to third-party services. In a script, `clientHandler` is wrapped within the global object `http`.

  Default: The default ClientHandler.

## Available objects

The following global objects are available to scripts:

* Any parameters passed as args

  You can use the configuration to pass parameters to the script by specifying an args object.

  The args object is a map whose values can be scalars, arrays, and objects. The args object can reference objects defined in the heap by using expressions, for example, `"${heap['ObjectName']}"`.

  The values for script arguments can be defined as configuration expressions, and evaluated at configuration time.

  Script arguments cannot refer to `context` and `request`, but `context` and `request` variables can be accessed directly within scripts.

  Take care when naming keys in the args object. If you reuse the name of another global object, cause the script to fail and PingGateway to return a response with HTTP status code 500 Internal Server Error.

- All heap objects

  The heap object configuration, described in [Heap objects](heap-objects.html).

* `openig`

  An implicit object that provides access to the environment when expressions are evaluated.

- `attributes`

  The [attributes](../_attachments/apidocs/org/forgerock/services/context/AttributesContext.html) object provides access to a context map of arbitrary attributes, which is a mechanism for transferring transient state between components when processing a single request.

  Use `session` for maintaining state between successive requests from the same logical client.

* `builder`

  For ScriptableJwtValidatorCustomizer only.

  Used by the ScriptableJwtValidatorCustomizer and [JwtValidationFilter](JwtValidationFilter.html) to create constraints to test JWT claims and sub-claims. The purpose of the ScriptableJwtValidatorCustomizer is to enrich the `builder` object.

  For information about methods to enrich the `builder` instance, refer to [JwtValidator.Builder](../_attachments/apidocs/org/forgerock/openig/tools/jwt/validation/JwtValidator.Builder.html).

- `constraints`

  The [constraints](../_attachments/apidocs/org/forgerock/openig/tools/jwt/validation/Constraints.html) object, all its static methods, `constant(String)`, and `claim(String)`.

  Use this object for JWT validation with the `customizer` property of [JwtValidationFilter](JwtValidationFilter.html).

  `claim(String)` must be followed by one of the following methods: `asString()`, `asInteger()`, `asLong()`, `asDouble()`, `asBoolean()`, `as(yourCustomJsonValueTransformer)`

* `context`

  The processing [context](../_attachments/apidocs/org/forgerock/services/context/Context.html).

  This context is the leaf of a chain of contexts. It provides access to other Context types, such as SessionContext, AttributesContext, and ClientContext, through the `context.asContext(ContextClass.class)` method.

- `contexts`

  a map\<string, context> object. For information, refer to [PingGateway context reference](Contexts.html).

* `request`

  The HTTP [request](../_attachments/apidocs/org/forgerock/http/protocol/Request.html).

  |   |                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
  | - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | The `request.form` method, used in scripts to read or set query and form parameters, is deprecated. Use the following replacement settings:- `Request.getQueryParams()` to read query parameters

  - `Entity.getForm()` to read form parameters

  - `Entity.setForm()` to set form parametersFor more information, refer to the [Deprecated](https://docs.pingidentity.com/pinggateway/release-notes/deprecated.html) section of the *Release Notes*. |

- `globals`

  This object is a [Map](https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html) that holds variables that persist across successive invocations.

* `http`

  An embedded client for making outbound HTTP requests, which is an [org.forgerock.http.Client](../_attachments/apidocs/org/forgerock/http/Client.html).

  If a `"clientHandler"` is set in the configuration, then that Handler is used. Otherwise, the default ClientHandler configuration is used.

  For information, refer to [PingGateway handlers](Handlers.html).

- `logger`

  The [logger](https://www.slf4j.org/api/org/slf4j/Logger.html) object provides access to a unique SLF4J logger instance for scripts, where the logger instance is named with the script name.

  For information about logging for scripts, refer to [Logging in scripts](../maintenance-guide/logging.html#logging-scripts).

* `next`

  The object named `next` refers to the next element in the chain, which can be the following filter or the terminal handler. If the next object in the chain is a filter, PingGateway wraps it in a handler.

- `session`

  The [session](../_attachments/apidocs/org/forgerock/http/session/SessionContext.html) object provides access to the session context, which is a mechanism for maintaining state when processing a successive requests from the same logical client or end user.

  Use `attributes` for transferring transient state between components when processing a single request.

## Imported classes

The following classes are imported automatically for Groovy scripts:

* [org.forgerock.http.Client](../_attachments/apidocs/org/forgerock/http/Client.html)

* [org.forgerock.http.Filter](../_attachments/apidocs/org/forgerock/http/Filter.html)

* [org.forgerock.http.Handler](../_attachments/apidocs/org/forgerock/http/Handler.html)

* [org.forgerock.http.protocol.Header](../_attachments/apidocs/org/forgerock/http/protocol/Header.html)

* [org.forgerock.openig.filter.throttling.ThrottlingRate](../_attachments/apidocs/org/forgerock/openig/filter/throttling/ThrottlingRate.html)

* [org.forgerock.http.util.Uris](../_attachments/apidocs/org/forgerock/http/util/Uris.html)

* [org.forgerock.util.AsyncFunction](../_attachments/apidocs/org/forgerock/util/AsyncFunction.html)

* [org.forgerock.util.Function](../_attachments/apidocs/org/forgerock/util/Function.html)

* [org.forgerock.util.promise.NeverThrowsException](../_attachments/apidocs/org/forgerock/util/promise/NeverThrowsException.html)

* [org.forgerock.util.promise.Promise](../_attachments/apidocs/org/forgerock/util/promise/Promise.html)

* [org.forgerock.util.promise.Promises](../_attachments/apidocs/org/forgerock/util/promise/Promises.html)

* [org.forgerock.services.context.Context](../_attachments/apidocs/org/forgerock/services/context/Context.html)

* org.forgerock.http.protocol.\*

* [org.forgerock.http.oauth2.AccessTokenInfo](../_attachments/apidocs/org/forgerock/http/oauth2/AccessTokenInfo.html)

* [org.forgerock.json.JsonValue](../_attachments/apidocs/org/forgerock/json/JsonValue.html), and all its static methods, including `json(Object)`, `array(Object…​)`, `object(fields…​)`, and `field(String, Object)`

* [org.forgerock.openig.util.JsonValues](../_attachments/apidocs/org/forgerock/openig/util/JsonValues.html) and all its static methods.

* [org.forgerock.openig.tools.jwt.validation.Constraints](../_attachments/apidocs/org/forgerock/openig/tools/jwt/validation/Constraints.html) and all its static methods.

## Examples

This documentation includes script examples in context, such as the following:

* [Discovery and dynamic registration with PingAM](../gateway-guide/oidc-dynamic.html)

* [Extend PingGateway](../configure/extending.html)

* [HttpBasicAuthenticationClientFilter](HttpBasicAuthenticationClientFilter.html)

* [Scripting required scopes with PingAM](../gateway-guide/oauth2-rs-script-scopes.html)

### Accessing secrets

The following example shows a script reading a password from a `SecretsProvider`:

```json
{
    "name": "SecretsApiExample",
    "condition": "${find(request.uri.path, '/secrets')}",
    "heap": [
        {
            "type": "SecretsProvider",
            "name": "LocalSecretsProvider",
            "config": {
                "stores": [
                    {
                        "name": "SecretsPasswords",
                        "type": "Base64EncodedSecretStore",
                        "_comment": "Base64-encoded 'password'",
                        "config": {
                            "secrets": {
                                "secret.password": "cGFzc3dvcmQ="
                            }
                        }
                    }
                ]
            }
        }
    ],
    "handler": {
        "name": "AccessPasswordAsGenericSecret",
        "type": "ScriptableHandler",
        "config": {
            "type": "application/x-groovy",
            "args": {
                "mySecretsProvider": "${heap['LocalSecretsProvider']}"
            },
            "source": [
                "import org.forgerock.secrets.GenericSecret",
                "import org.forgerock.secrets.Purpose",
                "Purpose<GenericSecret> purpose = Purpose.purpose('secret.password', GenericSecret.class)",
                "mySecretsProvider",
                "    .getActiveSecret(purpose)",
                "    .then(password -> password.revealAsUtf8(String::new))",
                "    .then(password -> new Response(Status.OK).setEntity('Secret password: ' + password))"
            ]
        }
    }
}
```

Source: [secrets.json](../_attachments/config/routes/secrets.json)

When you browse to this route, PingGateway displays `Secret password: password`.

Learn more about the secrets API in the [Javadoc](../_attachments/apidocs/org/forgerock/secrets/package-summary.html).

## More information

* [ScriptableFilter](ScriptableFilter.html), [org.forgerock.openig.filter.ScriptableFilter](../_attachments/apidocs/org/forgerock/openig/filter/ScriptableFilter.html), and [org.forgerock.http.Filter](../_attachments/apidocs/org/forgerock/http/Filter.html)

* [ScriptableHandler](ScriptableHandler.html), [org.forgerock.openig.handler.ScriptableHandler](../_attachments/apidocs/org/forgerock/openig/handler/ScriptableHandler.html), and [org.forgerock.http.Handler](../_attachments/apidocs/org/forgerock/http/Handler.html)

* [ScriptableThrottlingPolicy](ScriptableThrottlingPolicy.html), [org.forgerock.openig.filter.throttling.ScriptableThrottlingPolicy.Heaplet](../_attachments/apidocs/org/forgerock/openig/filter/throttling/ScriptableThrottlingPolicy.Heaplet.html), and [org.forgerock.openig.filter.throttling.ThrottlingPolicy](../_attachments/apidocs/org/forgerock/openig/filter/throttling/ThrottlingPolicy.html)

* `ScriptableResourceAccess` in [OAuth2ResourceServerFilter](OAuth2ResourceServerFilter.html), [org.forgerock.openig.filter.oauth2.ScriptableResourceAccess](../_attachments/apidocs/org/forgerock/openig/filter/oauth2/ScriptableResourceAccess.html), and [org.forgerock.http.oauth2.ResourceAccess](../_attachments/apidocs/org/forgerock/http/oauth2/ResourceAccess.html)

* `ScriptableAccessTokenResolver` in [OAuth2ResourceServerFilter](OAuth2ResourceServerFilter.html), [org.forgerock.openig.filter.oauth2.ScriptableAccessTokenResolver](../_attachments/apidocs/org/forgerock/openig/filter/oauth2/ScriptableAccessTokenResolver.html), and [org.forgerock.http.oauth2.AccessTokenResolver](../_attachments/apidocs/org/forgerock/http/oauth2/AccessTokenResolver.html)

* `ScriptableJwtValidatorCustomizer` in [JwtValidationFilter](JwtValidationFilter.html) and [org.forgerock.openig.filter.jwt.ScriptableJwtValidatorCustomizer](../_attachments/apidocs/org/forgerock/openig/filter/jwt/ScriptableJwtValidatorCustomizer.html)
