---
title: ReverseProxyHandler
description: Proxy requests to protected applications. When PingGateway relays the request to the protected application, PingGateway is acting as a client of the application. PingGateway is client-side.
component: pinggateway
version: 2026
page_id: pinggateway:reference:ReverseProxyHandler
canonical_url: https://docs.pingidentity.com/pinggateway/2026/reference/ReverseProxyHandler.html
revdate: 2026-01-26T12:00:00Z
section_ids:
  ReverseProxyHandler-usage: Usage
  ReverseProxyHandler-properties: Properties
  ReverseProxyHandler-vertx: vertx
  ReverseProxyHandler-connections: connections
  ReverseProxyHandler-waitQueueSize: waitQueueSize
  ReverseProxyHandler-connectionTimeout: connectionTimeout
  ReverseProxyHandler-connectionTimeToLive: connectionTimeToLive
  ReverseProxyHandler-connectionShutdownGracePeriod: connectionShutdownGracePeriod
  ReverseProxyHandler-protocolVersion: protocolVersion
  ReverseProxyHandler-http2PriorKnowledge: http2PriorKnowledge
  ReverseProxyHandler-proxyOptions: proxyOptions
  ReverseProxyHandler-propagateDisconnection: propagateDisconnection
  ReverseProxyHandler-soTimeout: soTimeout
  ReverseProxyHandler-temporaryStorage: temporaryStorage
  ReverseProxyHandler-tls: tls
  ReverseProxyHandler-retries: retries
  ReverseProxyHandler-circuitBreaker: circuitBreaker
  ReverseProxyHandler-websocket: websocket
  ReverseProxyHandler-graceful-close: Close connections gracefully
  ReverseProxyHandler-moreinfo: More information
---

# ReverseProxyHandler

Proxy requests to protected applications. When PingGateway relays the request to the protected application, PingGateway is acting as a client of the application. PingGateway is *client-side*.

Consider the following comparison of the ClientHandler and ReverseProxyHandler:

|                                                         | ClientHandler                                                                                                                                                                                                       | ReverseProxyHandler                                                                                          |
| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Use this handler to …​                                  | Send requests to third-party services accessed within a route. The service can be AM or an HTTP API. The service can be an HTTP endpoint, such as AM, IDM, PingOne Advanced Identity Cloud, or any custom HTTP API. | Send requests to the final service accessed by a route. The service can be the final downstream application. |
| If the service doesn't respond in time, this handler …​ | Propagates the error through the Promise flow\.If the error is not handled within the route, for example, by a FailureHandler, the handler returns a `500 Internal Server Error` response.                          | Stops processing the request, and returns a `502 Bad Gateway` response.                                      |

When uploading or downloading large files, prevent timeout issues by increasing the value of `soTimeout`, and using a streaming mode, as follows:

Configure the `streamingEnabled` property of [AdminHttpApplication](RequiredConfiguration.html).

## Usage

```none
{
  "name": string,
  "type": "ReverseProxyHandler",
  "config": {
    "vertx": object,
    "connections": configuration expression<number>,
    "waitQueueSize": configuration expression<number>,
    "soTimeout": configuration expression<duration>,
    "connectionTimeout": configuration expression<duration>,
    "connectionTimeToLive": configuration expression<duration>,
    "connectionShutdownGracePeriod": configuration expression<duration>,
    "protocolVersion": configuration expression<enumeration>,
    "http2PriorKnowledge": configuration expression<boolean>,
    "proxyOptions": ProxyOptions reference,
    "propagateDisconnection": configuration expression<boolean>,
    "temporaryStorage": TemporaryStorage reference,
    "tls": ClientTlsOptions reference,
    "retries": {
      "enabled": configuration expression<boolean>,
      "condition": runtime condition<boolean>,
      "executor": ScheduledExecutorService reference,
      "count": configuration expression<number>,
      "delay": configuration expression<duration>,
      "runtimeExceptionCondition": runtime condition<boolean>
    },
    "circuitBreaker": {
      "enabled": configuration expression<boolean>,
      "maxFailures":  configuration expression<integer>,
      "slidingCounter": {
        "size": configuration expression<number>
      },
      "openDuration": configuration expression<duration>,
      "openHandler": Handler reference,
      "executor":  ScheduledExecutorService reference
    },
    "websocket": {
      "enabled": configuration expression<boolean>,
      "maxConnections": configuration expression<number>,
      "connectionTimeout": configuration expression<duration>,
      "soTimeout": configuration expression<duration>,
      "tls": ClientTlsOptions reference,
      "proxyOptions": ProxyOptions reference
    }
  }
}
```

## Properties

### vertx

`"vertx"`: *[object](preface.html#definition-object), optional*

Vert.x-specific configuration for the handler where PingGateway doesn't provide its own first-class configuration. Learn more about Vert.x options in [HttpClientOptions](https://vertx.io/docs/5.0.10/apidocs/io/vertx/core/http/HttpClientOptions.html).

The `vertx` object is read as a map, and values are evaluated as configuration expressions.

For properties where PingGateway provides its own first-class configuration, Vert.x configuration options are disallowed and the PingGateway configuration option takes precedence over Vert.x options configured in `vertx`. The following Vert.x configuration options are disallowed client-side:

* `alpnVersions`

* `connectTimeout`

* `enabledCipherSuites`

* `enabledSecureTransportProtocols`

* `http2ClearTextUpgrade`

* `idleTimeout`

* `idleTimeoutUnit`

* `keyCertOptions`

* `keyStoreOptions`

* `maxWaitQueueSize`

* `pemKeyCertOptions`

* `pemTrustOptions`

* `pfxKeyCertOptions`

* `pfxTrustOptions`

* `port`

* `protocolVersion`

* `proxyOptions`

* `ssl`

* `trustOptions`

* `trustStoreOptions`

* `useAlpn`

* `verifyHost`

The following example configures the Vert.x configuration when PingGateway is acting client-side:

```json
{
  "vertx": {
    "maxWebSocketFrameSize": 128000,
    "maxWebSocketMessageSize": 256000,
    "compressionLevel": 4,
    "maxHeaderSize": 16384
  }
}
```

The following example configures HTTP/2 connections when PingGateway is acting client-side. The configuration allows PingGateway to make HTTP/2 requests with large headers:

```json
{
  "vertx": {
    "initialSettings": {
      "maxHeaderListSize": 16384
    }
  }
}
```

The following example sets a timeout for the DNS cache, so PingGateway can respond more quickly to DNS changes. Using [AddressResolverOptions](https://vertx.io/docs/5.0.10/apidocs/io/vertx/core/dns/AddressResolverOptions.html), it sets a maxiumum time-to-live (TTL) of 10 seconds for DNS responses:

```json
{
  "vertx": {
    "addressResolverOptions": {
      "cacheMaxTimeToLive": 10
    }
  }
}
```

When PingGateway establishes a new connection, it uses the DNS cache to resolve the hostname. After the maximum TTL, PingGateway performs a new DNS lookup to get the most up-to-date IP address for the hostname.

### connections

`"connections"`: *configuration expression<[number](preface.html#definition-number)>, optional*

The maximum number of concurrent HTTP connections in the client connection pool.

This setting interacts with the [waitQueueSize](#ReverseProxyHandler-waitQueueSize).

Default: 64

### waitQueueSize

`"waitQueueSize"`: *configuration expression<[number](preface.html#definition-number)>, optional*

The maximum number of outbound requests allowed to queue when no downstream connections are available. Outbound requests received when the queue is full are rejected.

Use this property to limit memory use when there is a backlog of outbound requests; for example, when the protected application or third-party service is slow.

Configure `waitQueueSize` in accord with the [connections](#ReverseProxyHandler-connections) setting:

* Not set (default): The wait queue is calculated as the square of `connections`.

  * If `connections` isn't configured, then its default of `64` is used, giving the `waitQueueSize` of `4096`.

  * If the square of `connections` exceeds the maximum integer value for the Java JVM, the maximum integer value for the Java JVM is used.

* `-1`: The wait queue is unlimited. Requests received when there are no available connections are queued without limit.

* `0`: There is no wait queue. Requests received when there are no available connections are rejected.

* A value that is less than the square of `connections`:

  When the configuration is loaded, the configured value is used. PingGateway generates a warning that the `waitQueueSize` is too small for the `connections` size and recommends a different value.

* A value where `waitQueueSize` plus `connections` exceeds the maximum integer value for the Java JVM:

  When the configuration is loaded, the `waitQueueSize` is reduced to the maximum integer value for the Java JVM minus the value of `connections`. PingGateway logs a warning.

Consider the following example configuration with `connections` and `waitQueueSize`:

```json
{
  "handler" : {
    "name" : "proxy-handler",
    "type" : "ReverseProxyHandler",
    "MyCapture" : "all",
    "config": {
      "soTimeout": "10 seconds",
      "connectionTimeout": "10 seconds",
      "connections": 64,
      "waitQueueSize": 100
    }
  },
  "baseURI" : "https://app.example.com:8444",
  "condition" : "${find(request.uri.path, '/')}"
}
```

PingGateway can propagate the request to the sample application using 64 connections. When the connections are consumed, up to 100 requests are queued until a connection is freed. Effectively PingGateway can accommodate 164 requests, although user concurrency delay means more may be handled. Requests received when the waitQueue is full are rejected.

Default: Not set

### connectionTimeout

`"connectionTimeout"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

Time to wait to establish a connection, expressed as a duration

Default: 10 seconds

### connectionTimeToLive

`"connectionTimeToLive"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

Time before a connection is closed, expressed as a duration.

Default: no limit

### connectionShutdownGracePeriod

`"connectionShutdownGracePeriod"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

Time to wait beyond ["connectionTimeToLive"](#ReverseProxyHandler-connectionTimeToLive) before shutting down the connection, expressed as a duration.

Default: The value of ["soTimeout"](#ReverseProxyHandler-soTimeout) (default: 10 seconds)

### protocolVersion

`"protocolVersion"`: *configuration expression<[enumeration](preface.html#definition-enumeration)>, optional*

The version of HTTP protocol to use when processing requests:

* `HTTP/2`:

  * For HTTP, process requests using HTTP/1.1.

  * For HTTPS, process requests using HTTP/2.

* `HTTP/1.1`:

  * For HTTP and HTTPS, process requests using HTTP/1.1.

* Not set:

  * For HTTP, process requests using HTTP/1.1.

  * For HTTPS with `alpn` enabled in ClientTlsOptions, process requests using HTTP/1.1 with an HTTP/2 upgrade request. If the targeted server can use HTTP/2, the client uses HTTP/2.

    For HTTPS with `alpn` disabled in ClientTlsOptions, process requests using HTTP/1.1 without an HTTP/2 upgrade request.

    Note that `alpn` is enabled by default in ClientTlsOptions.

Default: Not set

|   |                                                                                                                                                                                                                                                                                                                                     |
| - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | In HTTP/1.1 request messages, a `Host` header is required to specify the host and port number of the requested resource. In HTTP/2 request messages, the `Host` header isn't available.In scripts or custom extensions that use HTTP/2, use `UriRouterContext.originalUri.host` or `UriRouterContext.originalUri.port` in requests. |

### http2PriorKnowledge

`"http2PriorKnowledge"`: *configuration expression<[boolean](preface.html#definition-boolean)>, optional*

A flag for whether the client should have prior knowledge that the server supports HTTP/2. This property is for cleartext (non-TLS requests) only and is used only when `protocolVersion` is HTTP/2.

* `false`: The client checks whether the server supports HTTP/2 by sending an HTTP/1.1 request to upgrade the connection to HTTP/2:

  * If the server supports HTTP/2, the server upgrades the connection to HTTP/2 and later requests are over HTTP/2.

  * If the server doesn't support HTTP/2, the connection isn't upgraded and later requests are over HTTP/1.1.

* `true`: The client doesn't check that the server supports HTTP/2. The client sends HTTP/2 requests to the server, assuming that the server supports HTTP/2.

Default: `false`

### proxyOptions

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

A proxy server to which requests can be submitted. Use this property to relay requests to other parts of the network. For example, use it to submit requests from an internal network to the internet.

Provide the name of a [ProxyOptions](ProxyOptions.html) object defined in the heap or an inline configuration.

Default: A heap object named `ProxyOptions`.

### propagateDisconnection

`"propagateDisconnection"`: *configuration expression<[boolean](preface.html#definition-boolean)>, optional*

Use this setting to stop streaming content to a browser that disconnects.

When `"propagateDisconnection": true`, PingGateway disconnects from the protected application when:

* The user-agent disconnects from PingGateway.

* [Streaming is enabled](AdminHttpApplication.html#AdminHttpApplication-streamingEnabled) for PingGateway.

* The response includes the header `Transfer-Encoding: chunked`.

When changing this setting, also consider [reducing logging when propagating disconnections](../maintenance-guide/logging.html#logging-propagation).

Default: `false`

### soTimeout

`"soTimeout"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

Socket timeout, after which stalled connections are destroyed, expressed as a duration.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | * If the logs record `SocketTimeoutException` errors when you upload or download large files, increase `soTimeout`.

* When [streaming is enabled](AdminHttpApplication.html#AdminHttpApplication-streamingEnabled) and PingGateway acts as a reverse proxy for a client application receiving few or infrequent [server-side events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events), the default `soTimeout` can cause PingGateway to terminate the connection. For quiet SSE connections:

  * Set a high `soTimeout` value.

  * Use a server-side heartbeat mechanism to keep the connection active, for example, by periodically sending the comment delimiter `:`, which the client ignores.

  * Implement a retry mechanism in the client application to reconnect when the connection is closed. |

Default: 10 seconds

### temporaryStorage

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

The [TemporaryStorage](TemporaryStorage.html) object to buffer the request and response when the `streamingEnabled` property of [admin.json](AdminHttpApplication.html) is `false`.

Default: A heap object named `TemporaryStorage`

### tls

`tls`: *ClientTlsOptions [reference](preface.html#definition-reference), optional*

Configure [ClientTlsOptions](ClientTlsOptions.html) for connections to TLS-protected endpoints.

Define the object inline or in the heap.

Default: Connections to TLS-protected endpoints aren't configured.

### retries

`"retries"`: *[object](preface.html#definition-object), optional*

Enable and configure retry for requests.

During the execution of a request to a remote server, if a condition is met, a runtime exception occurs, or a matching runtime exception condition is met, PingGateway waits for a delay, then schedules a new execution of the request. PingGateway tries until the allowed number of retries is reached or the execution succeeds.

A warning-level entry is logged if all retry attempts fail. A debug-level entry is logged if a retry succeeds.

The following example configures a retry when a downstream component returns HTTP 502 Bad Gateway:

```none
"retries": {
    "enabled": true,
    "condition": "${response.status.code == 502}"
}
```

The following example configures the handler to retry the request only once after a 1-minute delay:

```json
{
  "retries": {
    "count": 1,
    "delay": "1 minute"
  }
}
```

The following example configures the handler to retry the request at most 20 times per second:

```json
{
  "retries": {
    "count": 20,
    "delay": "1 second"
  }
}
```

The following example retries the request only when a runtime expression for an HTTP/2 GOAWAY error occurs:

```json
{
    "retries": {
        "enabled": true,
        "runtimeExceptionCondition": "${exception.message.contains(\"GOAWAY\")}"
    }
}
```

The following example configures the handler to retry the request 5 times every 10 seconds (default values) with a dedicated executor:

```json
{
  "retries": {
    "executor": {
      "type": "ScheduledExecutorService",
      "config": {
        "corePoolSize": 20
      }
    }
  }
}
```

* `"enabled"`: *configuration expression<[boolean](preface.html#definition-boolean)>, optional*

  Enable retries.

  Default: `true`

- `"condition"`: *runtime condition<[boolean](preface.html#definition-boolean)>, optional*

  An inline PingGateway [condition](Conditions.html) to define a condition based on the response, such as an error code.

  The condition is evaluated as follows:

  * If the condition's expression is `true`, PingGateway retries the request until the `count` is reached.

  * If the condition's expression is `false`, PingGateway retries the request only if a runtime exception occurs until the `count` is reached.

  Default: `false`

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

  The [ScheduledExecutorService](ScheduledExecutorService.html) to use for scheduling delayed execution of the request.

  Default: `ScheduledExecutorService`

- `"count"`: *configuration expression<[number](preface.html#definition-number)>, optional*

  The maximum number of retries to perform. After this threshold is passed and if the request is still not successful, the handler propagates the failure.

  Retries caused by any runtime exception or triggered condition are included in the count.

  Default: `5`

* `"delay"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

  The time to wait before retrying the request.

  After a failure to send the request, if the number of retries is below the threshold, a new attempt is scheduled with the executor service after this delay.

  Default: `10 seconds`

- `"runtimeExceptionCondition"`: *runtime condition<[boolean](preface.html#definition-boolean)>, optional*

  An inline [condition](Conditions.html) to define a condition when a runtime exception occurs. The `context`, `request`, and `exception` are available in the expression of the condition.

  * If the condition's expression is `true`, PingGateway retries the request until the value in `count` is reached.

  * If the condition's expression is `false`, PingGateway doesn't retry the request.

  Default: When this isn't set, retry when any runtime exception occurs.

### circuitBreaker

`"circuitBreaker"`: *[object](preface.html#definition-object), optional*

Enable and configure a circuit breaker to trip when the number of failures exceeds a configured threshold. Calls to downstream services are stopped and a runtime exception is returned. The circuit breaker is reset after the configured delay.

* `"enabled"`: *configuration expression<[boolean](preface.html#definition-boolean)>, optional*

  A flag to enable the circuit breaker.

  Default: `true`

- `"maxFailures"`: *configuration expression<[number](preface.html#definition-number)>, required*

  The maximum number of failed requests allowed in the window given by `size`, before the circuit breaker trips. The value must be greater than zero.

  |   |                                                                                                                                                                                                                                                                                                                                                                                                              |
  | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
  |   | When `retries` is set, the circuit breaker doesn't count retried requests as failures. Keep this in mind when you set `maxFailures`.In the following example, a request can fail and then be retried three times. If it fails the third retry, the request has failed four times, but the circuit breaker counts only one failure.```json
  {
    "retries": {
      "count": 3,
      "delay": "1 second"
    }
  }
  ``` |

* `"openDuration"`: *configuration expression<[duration](preface.html#definition-duration)>, required*

  The duration for which the circuit stays open after the circuit breaker trips. The `executor` schedules the circuit to be closed after this duration.

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

  A sliding window error counter. The circuit breaker trips when the number of failed requests in the number of requests given by `size` reaches `maxFailures`.

  The following image illustrates how the sliding window counts failed requests:

  ![Example sliding window error counter.](_images/sliding-window.svg)

  * `"size"`: *configuration expression<[number](preface.html#definition-number)>, required*

    The size of the sliding window in which to count errors.

    The value of `size` must be greater than zero and greater than the value of `maxFailures`, otherwise PingGateway throws an exception.

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

  The [Handler](Handlers.html) to call when the circuit is open.

  Default: A handler that throws a RuntimeException with a "circuit-breaker open" message

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

  A [ScheduledExecutorService](ScheduledExecutorService.html) to schedule closure of the circuit after the duration given by `openDuration`.

Default: The default `ScheduledExecutorService` in the heap

### websocket

`"websocket"`: *[object](preface.html#definition-object), optional*

Object to configure upgrade from HTTP or HTTPS protocol to [The WebSocket Protocol](https://www.rfc-editor.org/rfc/rfc6455).

Every key/value of the `websocket` object is evaluated as a configuration expression.

List the subprotocols proxied by PingGateway in the `vertx` property of [AdminHttpApplication (`admin.json`)](AdminHttpApplication.html). Learn more in [WebSocket traffic with PingAM](../gateway-guide/websocket.html).

* `"enabled"`: *configuration expression<[boolean](preface.html#definition-boolean)>,optional*

  Enable upgrade from HTTP protocol and HTTPS protocol to WebSocket protocol.

  Default: `false`

- `"maxConnections"`: *configuration expression<[number](preface.html#definition-number)>,optional*

  Maximum number of concurrent WebSocket connections in the connection pool.

  Default: 64

* `"connectionTimeout"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

  The maximum time allowed to establish a WebSocket connection.

  Default: The value of handler's main `connectionTimeout`.

- `"soTimeout"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

  The time after which stalled connections are destroyed.

  |   |                                                                                                                                                                               |
  | - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | If there can be long delays between messages, consider increasing this value. Alternatively, keep the connection active by using WebSocket ping messages in your application. |

  Default: The value of handler's main `soTimeout`.

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

  An [ClientTlsOptions](ClientTlsOptions.html) reference to configure connections to TLS-protected endpoints.

  Default: Use ClientTlsOptions defined for the handler

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

  A proxy server to which requests can be submitted. Use this property to relay requests to other parts of the network. For example, use it to submit requests from an internal network to the internet.

  Provide the name of a [ProxyOptions](ProxyOptions.html) object defined in the heap or an inline configuration.

  Default: A heap object named `ProxyOptions`.

## Close connections gracefully

By default, PingGateway doesn't explicitly set a time limit for closing idle connections.

You can set ["connectionTimeToLive"](#ReverseProxyHandler-connectionTimeToLive) and ["connectionShutdownGracePeriod"](#ReverseProxyHandler-connectionShutdownGracePeriod) to choose how long to keep idle connections and how long a grace period to allow before closing them.

When configuring PingGateway to close idle connections, keep the following in mind:

* When [streaming is enabled](AdminHttpApplication.html#AdminHttpApplication-streamingEnabled) and the client application shares connections to PingGateway, closing a connection affects all the requests that share it.

* When PingGateway closes a connection to a protected application, the closure affects multiple requests even when PingGateway isn't pipelining any requests. Closing one connection from PingGateway to an application results in the closure of one or more connections from the client application to PingGateway. This affects multiple client requests.

## More information

[org.forgerock.openig.handler.ReverseProxyHandlerHeaplet](../_attachments/apidocs/org/forgerock/openig/handler/ReverseProxyHandlerHeaplet.html)
