---
title: PingOne Protect integration with PingGateway
description: Integrate PingOne Protect risk evaluations with PingGateway to route requests based on low, medium, or high risk scores
component: pinggateway
version: 2026
page_id: pinggateway:pingone:risk
canonical_url: https://docs.pingidentity.com/pinggateway/2026/pingone/risk.html
revdate: 2025-07-03T16:53:36Z
keywords: ["Configuration", "Authentication", "Risk"]
page_aliases: ["identity-cloud-guide:risk.adoc"]
section_ids:
  risk_management: Risk management
  example_protect_against_session_degradation: "Example: protect against session degradation"
  before_you_begin: Before you begin
  configure_pinggateway: Configure PingGateway
  validation: Validation
  risk-self-managed: Self-managed AM
---

# PingOne Protect integration with PingGateway

Use PingOne Protect risk evaluations with web applications protected by PingGateway. PingGateway routes requests based on the level of risk PingOne Protect associates with them.

## Risk management

PingOne Protect monitors end-user requests and generates a risk score of low, medium, or high based on the user's activity and device context. You configure and fine-tune risk policies and train risk models prior to using PingGateway with PingOne Protect. Learn more in [Threat Protection using PingOne Protect](https://docs.pingidentity.com/pingone/threat_protection_using_pingone_protect/p1_protect_overview.html).

You configure PingGateway routes to react to risk scores from PingOne Protect dynamically. For example, if the risk score is medium, PingGateway can direct the user to complete additional verification. If the risk score is high, PingGateway can deny access to the resource instead.

The following sequence diagram shows the PingGateway configuration objects involved in a risk management flow:

* The [PingOneProtectEvaluationFilter](../reference/PingOneProtectEvaluationFilter.html) calls PingOne Protect.

* It populates the [PingOneProtectEvaluationContext](../reference/PingOneProtectEvaluationContext.html) based on the response.

* The [PingOneProtectThreatLevelRoutingHandler](../reference/PingOneProtectThreatLevelRoutingHandler.html) dispatches the request based on its risk level.

* After prompting the user to complete additional actions following a risk evaluation, the [PingOneProtectFeedbackSuccessFilter](../reference/PingOneProtectFeedbackSuccessFilter.html) or [PingOneProtectFeedbackFailureFilter](../reference/PingOneProtectFeedbackFailureFilter.html) can send feedback to PingOne Protect and override the risk level in the session context.

![Data flow with PingOne Protect for risk evaluation](_images/risk.svg)

1. The initial request enters a Chain configured for risk evaluation with PingOne Protect.

2. The PingOneProtectEvaluationFilter includes data about the request in an API call to PingOne Protect.

3. PingOne Protect provides a risk evaluation response.

4. The PingOneProtectEvaluationFilter populates the PingOneProtectEvaluationContext with the risk level based on the evaluation response and passes control to the PingOneProtectThreatLevelRoutingHandler.

5. -10. The PingOneProtectThreatLevelRoutingHandler dispatches the request based on the risk level. The downstream handler returns a response to the initial request that is appropriate for the risk level. The downstream handlers can prompt additional actions to verify the user's identity.

Although not shown in the sequence diagram, when a `medium` risk level leads to additional authentication steps and the user successfully completes the steps, a PingOneProtectFeedbackSuccessFilter included in the process updates PingOne Protect to indicate the successful outcome.

The sequence diagram also omits device profile data collection. When the PingOneProtectEvaluationFilter includes `"deviceProfile"` settings, PingGateway gathers profile data from the user-agent by sending it a self-submitting form page that uses JavaScript to retrieve the profile information. (If JavaScript is disabled in the browser, PingGateway can't get the device profile data.) PingGateway includes the device profile in PingOne Protect risk evaluation requests.

PingGateway runs at the outer edge of your systems, the place where all inbound traffic first arrives and all outbound traffic leaves, just inside the network infrastructure.

PingGateway is well-placed to capture signals about the traffic and its risk profile.

## Example: protect against session degradation

*Session degradation* arises when a valid user session gets used in unexpected ways, increasing the risk the session has been hijacked or otherwise compromised. Session degradation is why we can't let users stay signed in forever unless we can authenticate them again.

Together, PingGateway and PingOne Protect help you automate fine-grained risk evaluation, avoiding the distraction of additional authentication steps unless they're required for a risky request. Users stay signed in with their current session, which they experience as a **keep me signed in** feature. You nevertheless protect their assets from hijacking without needing constantly to verify their identity.

This example demonstrates risk management where the principal already has a valid session. The example doesn't demonstrate how to configure PingOne Protect.

When PingOne Protect returns a risk evaluation, PingGateway responds based on the risk level. This example demonstrates the following responses:

* High risk

  Deny access to the requested resource.

  Although not shown in this brief example, you could route the request to a honeypot.

* Medium risk

  Prompt the user to reauthenticate to verify their identity.

  The user can perform step up or transactional authentication at this point.

* Low risk

  Let the request pass through unchanged.

### Before you begin

* Configure PingOne Protect. Learn more in the [PingOne Protect](https://docs.pingidentity.com/pingone/threat_protection_using_pingone_protect/p1_protect_overview.html) documentation.

* Implement [CDSSO with PingOne Advanced Identity Cloud](../aic/cdsso.html) or [CDSSO for self-managed AM](../gateway-guide/cdsso.html). This example opts for CDSSO with PingOne Advanced Identity Cloud. When using self-managed AM, also read [Self-managed AM](#risk-self-managed).

* For additional protection with medium-risk requests, implement [Step up authorization for a transaction](../aic/pep.html#stepup-session).

* Verify you can successfully authenticate with CDSSO to the sample application.

### Configure PingGateway

What follows extends the CDSSO route to protect against session degradation:

1. Sign on to the PingOne environment with PingOne Protect as an administrator and add an application for PingGateway.

   Use the following hints regarding non-default configuration settings:

   | Setting                     | Value                                 |
   | --------------------------- | ------------------------------------- |
   | Application Name            | PingGateway                           |
   | Application Type            | Worker                                |
   | Application profile > Roles | Environment Admin Identity Data Admin |

2. In the PingOne environment, find and record the values of the following settings:

   | Property                  | Description                                                                                                    |
   | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
   | Environment UUID          | This is `<env-uuid>` in other property examples.                                                               |
   | PingGateway client ID     | PingGateway credentials to access PingOne as the application you registered.                                   |
   | PingGateway client secret |                                                                                                                |
   | Policy set UUID           | The PingOne Protect policy for risk evaluation requests.                                                       |
   | Service endpoint          | For risk evaluation and feedback service requests.Example: `https://api.pingone.eu/v1/environments/<env-uuid>` |
   | Token endpoint            | For PingGateway to get an access token.Example: `https://auth.pingone.eu/<env-uuid>/as/token`                  |

3. In the PingGateway [AdminHttpApplication (`admin.json`)](../reference/AdminHttpApplication.html) file, make sure the maximum total headers size is large enough to accommodate request headers for the device profile cookies.

   After PingGateway collects device profile data, it stores the data in cookies on the user-agent. The user-agent returns these to PingGateway in the `Cookie` request header. Set the `maxTotalHeadersSize` for the PingGateway server ports large enough to avoid HTTP 431 Request Header Fields Too Large errors; for example:

   ```json
   "connectors": [
     {
       "port": 8080,
       "maxTotalHeadersSize": 32768
     },
     {
       "port": 8443,
       "maxTotalHeadersSize": 32768,
       "tls": "TlsConf"
     }
   ],
   ```

   You can skip this step if you don't use `"deviceProfile"` settings in the PingOneProtectEvaluationFilter.

4. Set an environment variable for the PingGateway client secret.

   PingGateway uses a SystemAndEnvSecretStore to retrieve the client secret, so you must base64-encode the value you found in the PingOne application profile:

   ```console
   $ export CLIENT_SECRET_ID='<base-64-encoded-client-secret>'
   ```

5. Restart PingGateway to load the updated `admin.json` settings and the environment variable.

6. Update the CDSSO route to add risk management:

   ```json
   {
     "name": "risk",
     "baseURI": "https://app.example.com:8444/login",
     "condition": "${find(request.uri.path, '^/home/cdsso')}",
     "properties": {
       "amInstanceUrl": "https://myTenant.forgeblocks.com/am",
       "clientId": "my-application-client-id",
       "policySetId": "my-policy-set-id",
       "serviceEndpoint": "https://api.pingone.eu/v1/environments/my-environment-id",
       "tokenEndpoint": "https://auth.pingone.eu/my-environment-id/as/token"
     },
     "heap": [
       {
         "name": "SystemAndEnvSecretStore-1",
         "type": "SystemAndEnvSecretStore"
       },
       {
         "name": "AmService-1",
         "type": "AmService",
         "config": {
           "url": "&{amInstanceUrl}",
           "realm": "/alpha",
           "agent": {
             "username": "ig_agent",
             "passwordSecretId": "agent.secret.id"
           },
           "secretsProvider": "SystemAndEnvSecretStore-1",
           "sessionCache": {
             "enabled": false
           }
         }
       },
       {
         "name": "ClientCredentialsOAuth2ClientFilter-1",
         "type": "ClientCredentialsOAuth2ClientFilter",
         "config": {
           "tokenEndpoint": "&{tokenEndpoint}",
           "scopes": [
             "openid",
             "profile",
             "email",
             "p1"
           ],
           "endpointHandler": {
             "name": "AccessTokenHandler",
             "type": "Chain",
             "config": {
               "filters": [
                 {
                   "type": "ClientSecretBasicAuthenticationFilter",
                   "config": {
                     "clientId": "&{clientId}",
                     "clientSecretId": "client.secret.id",
                     "secretsProvider": "SystemAndEnvSecretStore-1"
                   }
                 }
               ],
               "handler": "ForgeRockClientHandler"
             }
           }
         }
       },
       {
         "name": "RiskEndpointHandler",
         "type": "Chain",
         "config": {
           "filters": [
             "ClientCredentialsOAuth2ClientFilter-1"
           ],
           "handler": "ForgeRockClientHandler"
         }
       },
       {
         "name": "PingOneService-1",
         "type": "PingOneService",
         "config": {
           "serviceEndpoint": "&{serviceEndpoint}",
           "endpointHandler": "RiskEndpointHandler"
         }
       },
       {
         "name": "StepUpHandler",
         "type": "Chain",
         "config": {
           "filters": [
             {
               "name": "PolicyEnforcementFilter-1",
               "type": "PolicyEnforcementFilter",
               "config": {
                 "application": "PEP-CDSSO",
                 "ssoTokenSubject": "${contexts.cdsso.token}",
                 "amService": "AmService-1"
               }
             },
             {
               "name": "SuccessFeedbackFilter",
               "type": "PingOneProtectFeedbackSuccessFilter",
               "config": {
                 "pingOneService": "PingOneService-1",
                 "postEvaluationAssumedRiskLevel": "low"
               }
             }
           ],
           "handler": "ReverseProxyHandler"
         }
       },
       {
         "name": "FailureHandler",
         "type": "Chain",
         "config": {
           "filters": [
             {
               "name": "FailureFeedbackFilter",
               "type": "PingOneProtectFeedbackFailureFilter",
               "config": {
                 "pingOneService": "PingOneService-1"
               }
             }
           ],
           "handler": {
             "type": "StaticResponseHandler",
             "config": {
               "status": 403,
               "headers": {
                 "Content-Type": [
                   "text/plain; charset=UTF-8"
                 ]
               },
               "entity": "HTTP 403 Forbidden"
             }
           }
         }
       }
     ],
     "handler": {
       "type": "Chain",
       "config": {
         "filters": [
           {
             "name": "CrossDomainSingleSignOnFilter-1",
             "type": "CrossDomainSingleSignOnFilter",
             "config": {
               "redirectEndpoint": "/home/cdsso/redirect",
               "authCookie": {
                 "path": "/home",
                 "name": "ig-token-cookie"
               },
               "amService": "AmService-1"
             }
           },
           {
             "name": "PingOneProtectEvaluationFilter-1",
             "type": "PingOneProtectEvaluationFilter",
             "config": {
               "pingOneService": "PingOneService-1",
               "policySet": "&{policySetId}",
               "userId": "${contexts.cdsso.claimsSet.getClaim('subname')}",
               "nonEvaluatedUrls": "${find(request.uri.path, '/home/cdsso/redirect')}",
               "deviceProfile": {
                 "callbackEndpoint": "/home/cdsso/profilecallback"
               }
             }
           }
         ],
         "handler": {
           "name": "PingOneProtectThreatLevelRoutingHandler-1",
           "type": "PingOneProtectThreatLevelRoutingHandler",
           "config": {
             "levels": {
               "low": "ReverseProxyHandler",
               "medium": "StepUpHandler",
               "high": "FailureHandler"
             }
           }
         }
       }
     }
   }
   ```

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

   Notice the following features of the updated route:

   * The route properties use the settings you collected from the PingOne environment.

     Replace the placeholders in the route properties with the settings you collected.

   * The heap has an evaluation endpoint handler to get an access token for risk evaluation requests.

   * The PingOneProtectEvaluationFilter uses the evaluation endpoint handler to make the risk evaluation request and populate the PingOneProtectEvaluationContext (implicit in the configuration).

   * The PingOneProtectThreatLevelRoutingHandler uses the context to route the request based on the risk level:

     * Low-risk requests pass through unchanged.

     * Medium-risk requests use step up authorization for the request.

     * High-risk requests and requests where the PingOneProtectEvaluationFilter failed to update the context get denied.

### Validation

1. In your browser's privacy or incognito mode, go to <https://ig.ext.com:8443/home/cdsso>.

   PingOne Advanced Identity Cloud displays the login page.

2. Log in to PingOne Advanced Identity Cloud as the test user.

   After authentication, PingGateway gets an access token and uses it to make a risk evaluation request. The PingOneProtectThreatLevelRoutingHandler routes the result:

   * Low-risk requests go directly to the sample app.

   * Medium-risk requests prompt the user for the authorization passcode `7890`.

   * PingGateway denies access to other requests.

You've successfully demonstrated risk management to prevent session degradation. Adapt the route to the specifics of your use case.

## Self-managed AM

When you use transactional authorization with self-managed AM in this example, you must configure PingGateway to use *its* URI rather than the URI of the protected application when confirming the transaction.

You can do this by using a PolicyEnforcementFilter `"resourceUriProvider"` to rebase the protected URI on the PingGateway URI.

1. Add the following [ScriptableResourceUri.groovy](../_attachments/scripts/groovy/ScriptableResourceUri.groovy) script to PingGateway:

   * Linux

     `$HOME/.openig/scripts/groovy/ScriptableResourceUri.groovy`

   * Windows

     `%appdata%\OpenIG\scripts\groovy\ScriptableResourceUri.groovy`

   > **Collapse: ScriptableResourceUri.groovy**
   >
   > ```groovy
   > package scripts.groovy
   >
   > import org.forgerock.http.routing.UriRouterContext
   > import org.forgerock.http.util.Uris
   >
   > /**
   >  * Sample scriptable {@code RequestResourceUriProvider} (for use with a {@code PolicyEnforcementFilter}).
   >  *
   >  * This sample script "rebases" the in-flight request URI on top of the original URI. The term "in-flight" represents
   >  * the request's URI as it's manipulated as it progresses through the route. This is to ensure route components have had
   >  * the opportunity to act on the request prior to policy evaluation - e.g. to manipulate query parameters they may be
   >  * responsible for managing.
   >  *
   >  * <p>Example - indicates in-flight request URI's path, query and fragment retained and rebased on to original URI:
   >  * <ul>
   >  *     <li><b>original request URI</b>:  https://ig.ext.com:8443/home?param1=1&param2</li>
   >  *     <li><b>in-flight request URI</b>: http://app.example.com:8080/home?param2</li>
   >  *     <li><b>result (rebased) URI</b>:  https://ig.ext.com:8443/home?param2</li>
   >  * </ul>
   >  *
   >  * <p>Example config:
   >  * <pre>
   >  * {@code {
   >  *   "name" : "RebasingResourceUriProvider",
   >  *   "type" : "ScriptableResourceUriProvider",
   >  *   "config" : {
   >  *     "file" : "ScriptableResourceUri.groovy",
   >  *     "type": "application/x-groovy"
   >  *   }
   >  * }
   >  * }
   >  * </pre>
   >  *
   >  * <p>Example {@code PolicyEnforcementFilter} usage:
   >  * <pre>
   >  * {@code {
   >  *   "type" : "PolicyEnforcementFilter",
   >  *   "config" : {
   >  *     "amService" : "...",
   >  *     "application" : "...",
   >  *     "resourceUriProvider": "RebasingResourceUriProvider",
   >  *     ...
   >  *   }
   >  * }
   >  * }
   >  * </pre>
   >  */
   > def uriRouterContext = context.asContext(UriRouterContext.class)
   >
   > URI originalUri = uriRouterContext.getOriginalUri();
   > URI requestUri = request.getUri().asURI();
   > URI pathAndParams = new URI(null,
   >                             null,
   >                             requestUri.getPath(),
   >                             requestUri.getQuery(),
   >                             requestUri.getFragment());
   > logger.trace("ScriptableResourceUri rebasing {} with request parameters {}", originalUri, pathAndParams);
   > String rebasedUri = Uris.rebase(pathAndParams, originalUri).toASCIIString();
   > logger.trace("ScriptableResourceUri rebased to URI '{}'", rebasedUri);
   > return rebasedUri;
   > ```

2. Add a reference to the script in the route heap:

   ```json
   {
       "name": "RebasingResourceUriProvider",
       "type": "ScriptableResourceUriProvider",
       "config": {
           "file": "ScriptableResourceUri.groovy",
           "type": "application/x-groovy"
       }
   }
   ```

3. In the PolicyEnforcementFilter for the route, use the reference to the script in the `"resourceUriProvider"` setting:

   ```json
   {
       "name": "PolicyEnforcementFilter-1",
       "type": "PolicyEnforcementFilter",
       "config": {
           "application": "PEP-CDSSO",
           "ssoTokenSubject": "${contexts.cdsso.token}",
           "amService": "AmService-1",
           "resourceUriProvider": "RebasingResourceUriProvider"
       }
   }
   ```

4. Make sure the route's `"amInstanceUrl"` reflects your self-managed AM.

5. Save your changes to the route.

   After PingGateway reloads the route, you can validate the scenario with your self-managed AM deployment.
