---
title: Policy enforcement
description: IG as a policy enforcement point (PEP) uses the PolicyEnforcementFilter to intercept requests for a resource and provide information about the request to AM.
component: pinggateway
version: 2023.11
page_id: pinggateway:gateway-guide:policy-enforcement
canonical_url: https://docs.pingidentity.com/pinggateway/2026/gateway-guide/policy-enforcement.html
llms_txt: https://docs.pingidentity.com/pinggateway/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2023-06-07T15:12:25Z
keywords: ["Configuration", "Policy", "Authentication", "Authorization"]
superseded_by: https://docs.pingidentity.com/pinggateway/2026/gateway-guide/policy-enforcement.html
section_ids:
  about-pep: About policy enforcement
  deny_requests_without_advices: Deny requests without advices
  about-pep-advices-redirect: Deny requests with advices as parameters in a redirect response
  about-pep-advices-header: Deny requests with advices in a header
  pep: Enforce policy decisions from AM
  pep-sso: Enforce AM policy decisions in the same domain
  pep-sso-realm: Require users to authenticate to a specific realm
  pep-cdsso: Enforce AM policy decisions in different domains
  PEF-example: Enforce policy decisions using claimsSubject
  pep-evict-cache: Using WebSocket notifications to evict the policy cache
  stepup: Harden authorization with advice from AM
  stepup-sso-session: Step up the authentication level for an AM session
  stepup-sso-trx: Increase authorization for a single transaction
---

# Policy enforcement

## About policy enforcement

IG as a policy enforcement point (PEP) uses the PolicyEnforcementFilter to intercept requests for a resource and provide information about the request to AM.

AM as a policy decision point (PDP) evaluates requests based on their context and the configured policies. AM then returns decisions that indicate what actions are allowed or denied, as well as any advices, subject attributes, or static attributes for the specified resources.

For more information, refer to the [PolicyEnforcementFilter](../reference/Filters.html#PolicyEnforcementFilter) and AM's [Authentication and SSO](https://docs.pingidentity.com/pingam/7.4/am-authentication/preface.html) guide.

### Deny requests without advices

The following image shows a simplified flow of information when AM denies a request without advices.

![Flow of information for policy enforcement when AM allows or denies a request with no advices](_images/policydp-allowdeny-noadvices.svg)

### Deny requests with advices as parameters in a redirect response

The following image shows a simplified flow of information when AM denies a request with advices and IG returns the advices as parameters in a redirect response.

This is the default flow, most used for web applications.

![Flow of information when AM denies a request with advices in parameters](_images/policydp-noauthheader.svg)

### Deny requests with advices in a header

The following image shows a simplified flow of information when the request to IG includes an `x-authenticate-response` header with the value `header`. If the header has any other value, the flow in [Deny requests with advices as parameters in a redirect response](#about-pep-advices-redirect) takes place.

To change the name of the `x-authenticate-response` header, refer to the `authenticateResponseRequestHeader` property of the [PolicyEnforcementFilter](../reference/Filters.html#authenticateResponseRequestHeader).

In this flow, AM denies the request with advices, and IG sends the response with the advices in the `WWW-authenticate` header.

Use this method for SDKs and single page applications. Placing advices in a header gives these applications more options for handling the advices.

![Flow of information for policy enforcement when AM denies a request with advices in the \`x-authenticate-response\` header](_images/policydp-authheader.svg)

Consider the following example GET with an `x-authenticate-response` header with the value `HEADER`:

```json
[CONTINUED]GET https://ig.example.com:8443/home HTTP/1.1
[CONTINUED]accept-encoding: gzip, deflate
[CONTINUED]Connection: close
[CONTINUED]cookie: iPlanetDirectoryPro=0Dx...e3A.*....; amlbcookie=01
[CONTINUED]Host: ig.example.com:8443
[CONTINUED]x-authenticate-response: HEADER
```

IG returns a `WWW-Authenticate` header containing advices, as follows:

```json
HTTP/1.1 401 Unauthorized
WWW-Authenticate: SSOADVICE realm="/",advices="eyJ...XX0=",am_uri="http://openam.example.com:8080/am/"
transfer-encoding: chunked
connection: close
```

The advice decodes to a transaction condition advice:

```json
{"TransactionConditionAdvice":["493...3c4"]}
```

## Enforce policy decisions from AM

The following sections describe how to set up single sign on for requests in the same domain and in a different domain.

### Enforce AM policy decisions in the same domain

The following procedure gives an example of how to create a policy in AM and configure an agent that can request policy decisions, when IG and AM are in the same domain.

Before you start, set up and test the example in [Authenticate with SSO through the default authentication service](sso-cdsso.html#proc-sso).

1. Set up AM:

   1. In the AM admin UI, select [icon: key, set=fa]Authorization > Policy Sets > New Policy Set, and add a policy set with the following values:

      * Id : `PEP-SSO`

      * Resource Types : `URL`

   2. In the policy set, add a policy with the following values:

      * Name : `PEP-SSO`

      * Resource Type : `URL`

      * Resource pattern : `*://*:*/*`

      * Resource value : `http://app.example.com:8081/home/pep-sso*`

        This policy protects the home page of the sample application.

   3. On the Actions tab, add an action to allow HTTP `GET`.

   4. On the Subjects tab, remove any default subject conditions, add a subject condition for all `Authenticated Users`.

2. Set up IG:

   1. Set an environment variable for the IG agent password, and then restart IG:

      ```bash
      $ export AGENT_SECRET_ID='cGFzc3dvcmQ='
      ```

      The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.

   2. Add the following route to IG to serve the sample application .css and other static resources:

      * Linux

      * Windows

      ```
      $HOME/.openig/config/routes/00-static-resources.json
      ```

      ```
      %appdata%\OpenIG\config\routes\00-static-resources.json
      ```

      ```json
      {
        "name" : "00-static-resources",
        "baseURI" : "http://app.example.com:8081",
        "condition": "${find(request.uri.path,'^/css') or matchesWithRegex(request.uri.path, '^/.*\\\\.ico$') or matchesWithRegex(request.uri.path, '^/.*\\\\.gif$')}",
        "handler": "ReverseProxyHandler"
      }
      ```

   3. Add the following route to IG:

      * Linux

      * Windows

      ```
      $HOME/.openig/config/routes/04-pep.json
      ```

      ```
      %appdata%\OpenIG\config\routes\04-pep.json
      ```

      ```json
      {
        "name": "pep-sso",
        "baseURI": "http://app.example.com:8081",
        "condition": "${find(request.uri.path, '^/home/pep-sso')}",
        "heap": [
          {
            "name": "SystemAndEnvSecretStore-1",
            "type": "SystemAndEnvSecretStore"
          },
          {
            "name": "AmService-1",
            "type": "AmService",
            "config": {
              "agent": {
                "username": "ig_agent",
                "passwordSecretId": "agent.secret.id"
              },
              "secretsProvider": "SystemAndEnvSecretStore-1",
              "url": "http://am.example.com:8088/openam/"
            }
          }
        ],
        "handler": {
          "type": "Chain",
          "config": {
            "filters": [
              {
                "name": "SingleSignOnFilter-1",
                "type": "SingleSignOnFilter",
                "config": {
                  "amService": "AmService-1"
                }
              },
              {
                "name": "PolicyEnforcementFilter-1",
                "type": "PolicyEnforcementFilter",
                "config": {
                  "application": "PEP-SSO",
                  "ssoTokenSubject": "${contexts.ssoToken.value}",
                  "amService": "AmService-1"
                }
              }
            ],
            "handler": "ReverseProxyHandler"
          }
        }
      }
      ```

      For information about how to set up the IG route in Studio, refer to [Policy enforcement in Structured Editor](../studio-guide/examples-se.html#example-pep-sso-se) or [Protecting a web app with Freeform Designer](../studio-guide/examples-ff.html#example-pep-sso-ff).

      For an example route that uses `claimsSubject` instead of `ssoTokenSubject` to identify the subject, refer to [Example policy enforcement using claimsSubject](../reference/Filters.html#PEF-example).

3. Test the setup:

   1. If you are logged in to AM, log out and clear any cookies.

   2. Go to <http://ig.example.com:8080/home/pep-sso>.

      Because you have not previously authenticated to AM, the request does not contain a cookie with an SSO token. The SingleSignOnFilter redirects you to AM for authentication.

   3. Log in to AM as user `demo`, password `Ch4ng31t`.

      When you have authenticated, AM redirects you back to the request URL, and IG requests a policy decision using the AM session cookie.

      AM returns a policy decision that grants access to the sample application.

### Require users to authenticate to a specific realm

This example creates a policy that requires users to authenticate in a specific realm.

To reduce the attack surface on the top level realm, ForgeRock advises you to create federation entities, agent profiles, authorizations, OAuth2/OIDC, and STS services in a subrealm. For this reason, the AM policy, AM agent, and services are in a subrealm.

1. Set up AM:

   1. In the AM admin UI, click Realms, and add a realm named `alpha`. Leave all other values as default.

      For the rest of the steps in this procedure, make sure you are managing the alpha realm by checking that the [icon: cloud, set=fa]alpha icon is displayed on the top left.

   2. (From AM 6.5.3) Select Services > Add a Service, and add a Validation Service with the following Valid goto URL Resources:

      * `http://ig.example.com:8080/*`

      * `http://ig.example.com:8080/*?*`

   3. Select Applications > Agents > Identity Gateway and register an IG agent with the following values:

      * Agent ID: `ig_agent`

      * Password: `password`

        For AM 6.5.x and earlier versions, register an agent as described in [Register an IG agent in AM 6.5 and earlier](preface.html#register-agent-65).

        |   |                                                                                                                   |
        | - | ----------------------------------------------------------------------------------------------------------------- |
        |   | Use secure passwords in a production environment. Consider using a password manager to generate secure passwords. |

   4. (Optional) Authenticate the agent to AM as described in [Authenticate an IG agent to AM](preface.html#authenticate-agent-am).

      |   |                                                                                                                                                                                                                                  |
      | - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
      |   | IG agents are automatically authenticated to AM by a deprecated authentication module in AM. This step is currently optional, but will be required when authentication chains and modules are removed in a future release of AM. |

   5. Add a policy:

      1. Select [icon: key, set=fa]Authorization > Policy Sets > New Policy Set, and add a policy set with the following values:

         * Id : `PEP-SSO-REALM`

         * Resource Types : `URL`

      2. In the policy set, add a policy with the following values:

         * Name : `PEP-SSO-REALM`

         * Resource Type : `URL`

         * Resource pattern : `*://*:*/*`

         * Resource value : `http://app.example.com:8081/home/pep-sso-realm`

           This policy protects the home page of the sample application.

      3. On the Actions tab, add an action to allow HTTP `GET`.

      4. On the Subjects tab, remove any default subject conditions, add a subject condition for all `Authenticated Users`.

      5. On the Environments tab, add an environment condition that requires the user to authenticate to the [icon: cloud, set=fa]alpha realm:

         * Type : `Authentication to a Realm`

         * Authenticate to a Realm : `/alpha`

2. Set up IG:

   1. Add the following route to IG:

      * Linux

      * Windows

      ```
      $HOME/.openig/config/routes/04-pep-sso-realm.json
      ```

      ```
      %appdata%\OpenIG\config\routes\04-pep-sso-realm.json
      ```

      ```json
      {
        "name": "pep-sso-realm",
        "baseURI": "http://app.example.com:8081",
        "condition": "${find(request.uri.path, '^/home/pep-sso-realm')}",
        "heap": [
          {
            "name": "SystemAndEnvSecretStore-1",
            "type": "SystemAndEnvSecretStore"
          },
          {
            "name": "AmService-1",
            "type": "AmService",
            "config": {
              "agent": {
                "username": "ig_agent",
                "passwordSecretId": "agent.secret.id"
              },
              "secretsProvider": "SystemAndEnvSecretStore-1",
              "url": "http://am.example.com:8088/openam/",
              "realm": "/alpha"
            }
          }
        ],
        "handler": {
          "type": "Chain",
          "config": {
            "filters": [
              {
                "name": "SingleSignOnFilter-1",
                "type": "SingleSignOnFilter",
                "config": {
                  "amService": "AmService-1"
                }
              },
              {
                "name": "PolicyEnforcementFilter-1",
                "type": "PolicyEnforcementFilter",
                "config": {
                  "application": "PEP-SSO-REALM",
                  "ssoTokenSubject": "${contexts.ssoToken.value}",
                  "amService": "AmService-1"
                }
              }
            ],
            "handler": "ReverseProxyHandler"
          }
        }
      }
      ```

      Notice the following differences compared to `04-pep-sso.json`:

      * The AmService is in the `alpha` realm. That means that the user authenticates to AM in that realm.

      * The PolicyEnforcementFilter realm is not specified, so it takes the same value as the AmService realm. If refers to a policy in the AM `alpha` realm.

3. Test the setup:

   1. In a private browser, go to <http://ig.example.com:8080/home/pep-sso-realm>, and log in to AM as user `demo`, password `Ch4ng31t`.

      Because you are authenticating in the `alpha` realm, AM returns a policy decision that grants access to the sample application.

      If you were to send the request from a different realm, AM would redirect the request with an `AuthenticateToRealmConditionAdvice`.

### Enforce AM policy decisions in different domains

The following procedure gives an example of how to create a policy in AM and configure an agent that can request policy decisions, when IG and AM are in different domains.

Before you start, set up and test the example in [Cross-domain single sign-on](sso-cdsso.html#cdsso).

1. Set up AM:

   1. In the AM admin UI, select Applications > Agents > Identity Gateway, and change the redirect URL for `ig_agent_cdsso`:

      * Redirect URL for CDSSO : `https://ig.ext.com:8443/home/pep-cdsso/redirect`

   2. Select [icon: key, set=fa]Authorization > Policy Sets > New Policy Set, and add a policy set with the following values:

      * Id : `PEP-CDSSO`

      * Resource Types : `URL`

        * In the new policy set, add a policy with the following values:

      * Name : `CDSSO`

      * Resource Type : `URL`

      * Resource pattern : `*://*:*/*`

      * Resource value : `http://app.example.com:8081/home/pep-cdsso*`

        This policy protects the home page of the sample application.

      * On the Actions tab, add an action to allow HTTP `GET`.

      * On the Subjects tab, remove any default subject conditions, add a subject condition for all `Authenticated Users`.

2. Set up IG:

   1. Set an environment variable for the IG agent password, and then restart IG:

      ```bash
      $ export AGENT_SECRET_ID='cGFzc3dvcmQ='
      ```

      The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.

   2. Add the following route to IG to serve the sample application .css and other static resources:

      * Linux

      * Windows

      ```
      $HOME/.openig/config/routes/00-static-resources.json
      ```

      ```
      %appdata%\OpenIG\config\routes\00-static-resources.json
      ```

      ```json
      {
        "name" : "00-static-resources",
        "baseURI" : "http://app.example.com:8081",
        "condition": "${find(request.uri.path,'^/css') or matchesWithRegex(request.uri.path, '^/.*\\\\.ico$') or matchesWithRegex(request.uri.path, '^/.*\\\\.gif$')}",
        "handler": "ReverseProxyHandler"
      }
      ```

   3. Add the following route to IG:

      * Linux

      * Windows

      ```
      $HOME/.openig/config/routes/04-pep-cdsso.json
      ```

      ```
      %appdata%\OpenIG\config\routes\04-pep-cdsso.json
      ```

      ```json
      {
        "name": "pep-cdsso",
        "baseURI": "http://app.example.com:8081",
        "condition": "${find(request.uri.path, '^/home/pep-cdsso')}",
        "heap": [
          {
            "name": "SystemAndEnvSecretStore-1",
            "type": "SystemAndEnvSecretStore"
          },
          {
            "name": "AmService-1",
            "type": "AmService",
            "config": {
              "agent": {
                "username": "ig_agent_cdsso",
                "passwordSecretId": "agent.secret.id"
              },
              "secretsProvider": "SystemAndEnvSecretStore-1",
              "url": "http://am.example.com:8088/openam/"
            }
          }
        ],
        "handler": {
          "type": "Chain",
          "config": {
            "filters": [
              {
                "name": "CrossDomainSingleSignOnFilter-1",
                "type": "CrossDomainSingleSignOnFilter",
                "config": {
                  "redirectEndpoint": "/home/pep-cdsso/redirect",
                  "authCookie": {
                    "path": "/home",
                    "name": "ig-token-cookie"
                  },
                  "amService": "AmService-1"
                }
              },
              {
                "name": "PolicyEnforcementFilter-1",
                "type": "PolicyEnforcementFilter",
                "config": {
                  "application": "PEP-CDSSO",
                  "ssoTokenSubject": "${contexts.cdsso.token}",
                  "amService": "AmService-1"
                }
              }
            ],
            "handler": "ReverseProxyHandler"
          }
        }
      }
      ```

|   |                                                                                                                                                                                                  |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | When `verificationSecretId` is not configured, IG discovers and uses the AM JWK set to verify the signature of AM session tokens. If the JWK set isn't available, IG does not verify the tokens. |

1. Test the setup:

   1. If you are logged in to AM, log out and clear any cookies.

   2. Go to <https://ig.ext.com:8443/home/pep-cdsso>.

      If you have warnings that the site is not secure respond to the warnings to access the site.

      IG redirects you to AM for authentication.

   3. Log in to AM as user `demo`, password `Ch4ng31t`.

      When you have authenticated, AM redirects you back to the request URL, and IG requests a policy decision. AM returns a policy decision that grants access to the sample application.

### Enforce policy decisions using claimsSubject

This example is a variant of [Enforce AM policy decisions in the same domain](#pep-sso). It enforces a policy decision from AM, using `claimsSubject` instead of `ssoTokenSubject` to identify the subject.

1. Set up AM as described in [Enforce AM policy decisions in the same domain](#pep-sso).

2. In AM, select the policy you created in the previous step, and add a new resource:

   * Resource Type: `URL`

   * Resource pattern: `*://*:*/*`

   * Resource value: `http://app.example.com:8081/home/pep-claims`

3. In the same policy, add the following subject condition:

   * `Any of`

   * Type : `OpenID Connect/JwtClaim`

   * claimName : `iss`

   * claimValue : `am.example.com`

4. Set an environment variable for the IG agent password, and then restart IG:

   ```bash
   $ export AGENT_SECRET_ID='cGFzc3dvcmQ='
   ```

   The password is retrieved by a SystemAndEnvSecretStore, and must be base64-encoded.

5. Add the following route to IG to serve the sample application .css and other static resources:

   * Linux

   * Windows

   ```
   $HOME/.openig/config/routes/00-static-resources.json
   ```

   ```
   %appdata%\OpenIG\config\routes\00-static-resources.json
   ```

   ```json
   {
     "name" : "00-static-resources",
     "baseURI" : "http://app.example.com:8081",
     "condition": "${find(request.uri.path,'^/css') or matchesWithRegex(request.uri.path, '^/.*\\\\.ico$') or matchesWithRegex(request.uri.path, '^/.*\\\\.gif$')}",
     "handler": "ReverseProxyHandler"
   }
   ```

6. Add the following route to IG:

   * Linux

   * Windows

   ```
   $HOME/.openig/config/routes/04-pep-claims.json
   ```

   ```
   %appdata%\OpenIG\config\routes\04-pep-claims.json
   ```

   ```json
   {
     "name": "pep-claims",
     "baseURI": "http://app.example.com:8081",
     "condition": "${find(request.uri.path, '^/home/pep-claims')}",
     "heap": [
       {
         "name": "SystemAndEnvSecretStore-1",
         "type": "SystemAndEnvSecretStore"
       },
       {
         "name": "AmService-1",
         "type": "AmService",
         "config": {
           "url": "http://am.example.com:8088/openam",
           "agent": {
             "username": "ig_agent",
             "passwordSecretId": "agent.secret.id"
           },
           "secretsProvider": "SystemAndEnvSecretStore-1"
         }
       }
     ],
     "handler": {
       "type": "Chain",
       "config": {
         "filters": [
           {
             "name": "SingleSignOnFilter-1",
             "type": "SingleSignOnFilter",
             "config": {
               "amService": "AmService-1"
             }
           },
           {
             "name": "PolicyEnforcementFilter-1",
             "type": "PolicyEnforcementFilter",
             "config": {
               "application": "PEP-SSO",
               "claimsSubject": {
                 "sub": "${contexts.ssoToken.info.uid}",
                 "iss": "am.example.com"
               },
               "amService": "AmService-1"
             }
           }
         ],
         "handler": "ReverseProxyHandler"
       }
     }
   }
   ```

7. Go to <http://ig.example.com:8080/home/pep-claims>.

8. Log in to AM as user `demo`, password `Ch4ng31t`.

   AM returns a policy decision that grants access to the sample application.

### Using WebSocket notifications to evict the policy cache

When WebSocket notifications are enabled, IG receives notifications whenever AM creates, deletes, or changes a policy.

The following procedure gives an example of how to change the configuration in [Enforce AM policy decisions in the same domain](#pep-sso) and [Enforce AM policy decisions in different domains](#pep-cdsso) to evict outdated entries from the policy cache. For information about WebSocket notifications, refer to [WebSocket notifications](../maintenance-guide/tuning.html#amservice-websocket).

1. Set up and test the example in [Enforce AM policy decisions in the same domain](#pep-sso).

2. Websocket notifications are enabled by default. If they are disabled, enable them by adding the following configuration to the [AmService](../reference/AmService.html) in your route:

   ```json
   "notifications": {
     "enabled": true
   }
   ```

3. Enable policy cache in the [PolicyEnforcementFilter](../reference/PolicyEnforcementFilter.html) in your route:

   ```json
   "cache": {
     "enabled": true
   }
   ```

4. In `logback.xml` add the following logger for WebSocket notifications, and then restart IG:

   ```xml
   <logger name="org.forgerock.openig.tools.notifications.ws" level="TRACE" />
   ```

   For information, refer to [Changing the log level for different object types](../maintenance-guide/logging.html#logging-level-objects).

5. Go to <http://ig.example.com:8080/home/pep-sso>, and log in to AM as user `demo`, password `Ch4ng31t`.

6. In a separate terminal, log on to AM as admin, and change the PEP-SSO policy. For example, in the Actions tab, add an action to allow HTTP `DELETE`.

7. Note that the IG system logs are updated with Websocket notifications about the change:

   ```none
   ... | TRACE | vert.x-eventloop-thread-2 | o.f.o.t.n.w.SubscriptionService | @system | Received a message: { "topic": "/agent/policy", "timestamp": ..., "body": { "realm": "/", "policy": "PEP-SSO", "policySet": "PEP-SSO", "eventType": "UPDATE" } }
   ... | TRACE | vert.x-eventloop-thread-2 | o.f.o.t.n.w.SubscriptionService | @system | Received a notification: { "topic": "/agent/policy", "timestamp": ..., "body": { "realm": "/", "policy": "PEP-SSO", "policySet": "PEP-SSO", "eventType": "UPDATE" } }
   ```

## Harden authorization with advice from AM

To protect sensitive resources, AM policies can be configured with additional conditions to harden the authorization. When AM communicates these policy decisions to IG, the decision includes advices to indicate what extra conditions the user must meet.

Conditions can include requirements to access the resource over a secure channel, access during working hours, or to authenticate again at a higher authentication level. For more information, refer to AM's [Authorization guide](https://docs.pingidentity.com/pingam/7.4/am-authorization/preface.html).

The following sections build on the policies in [Enforce policy decisions from AM](#pep) to step up the authentication level:

### Step up the authentication level for an AM session

When you step up the authentication level for an AM session, the authorization is verified and then captured as part of the AM session, and the user agent is authorized to that authentication level for the duration of the AM session.

This section uses the policies you created in [Enforce AM policy decisions in the same domain](#pep-sso) and [Enforce AM policy decisions in different domains](#pep-cdsso), adding an authorization policy with a Authentication by Service environment condition. Except for the paths where noted, procedures for single domain and cross-domain are the same.

After the user agent redirects the user to AM, if the user is not already authenticated they are presented with a login page. If the user is already authenticated, or after they authenticate, they are presented with a second page asking for a verification code to meet the `AuthenticateToService` environment condition.

Before you start, set up one of the following examples in [Enforce AM policy decisions in the same domain](#pep-sso) or [Enforce AM policy decisions in different domains](#pep-cdsso).

1. In the AM admin UI, add an environment condition to the policy:

   1. Select a policy set:

      * For SSO, select [icon: key, set=fa]Authorization > Policy Sets > PEP-SSO.

      * For CDSSO, select [icon: key, set=fa]Authorization > Policy Sets > PEP-CDSSO.

   2. In the policy, select Environments, and add the following environment condition:

      * `All of`

      * Type : `Authentication by Service`

      * Authenticate to Service : `VerificationCodeLevel1`

2. Set up client-side and server-side scripts:

   1. Select [icon: code, set=fa]Scripts > Scripted Module - Client Side, and replace the default script with the following script:

      ```javascript
      autoSubmitDelay = 60000;

      function callback() {
          var parent = document.createElement("div");
          parent.className = "form-group";

          var label = document.createElement("label");
          label.className = "sr-only separator";
          label.setAttribute("for", "answer");
          label.innerText = "Verification Code";
          parent.appendChild(label);

          var input = document.createElement("input");
          input.className = "form-control input-lg";
          input.type = "text";
          input.placeholder = "Enter your verification code";
          input.name = "answer";
          input.id = "answer";
          input.value = "";
          input.oninput = function(event) {
              var element = document.getElementById("clientScriptOutputData");
              if (!element.value || element.value == "clientScriptOutputData") element.value = "{}";
              var json = JSON.parse(element.value);
              json["answer"] = event.target.value;
              element.value = JSON.stringify(json);
          };
          parent.appendChild(input);

          var fieldset = document.forms[0].getElementsByTagName("fieldset")[0];
          fieldset.prepend(parent);
      }

      if (document.readyState !== 'loading') {
          callback();
      } else {
          document.addEventListener("DOMContentLoaded", callback);
      }
      ```

      Leave all other values as default.

      This client-side script adds a field to the AM form, in which the user is required to enter a verification code. The script formats the entered code as a JSON object, as required by the server-side script.

   2. Select [icon: code, set=fa]Scripts > Scripted Module - Server Side, and replace the default script with the following script:

      ```javascript
      username = 'demo'
      logger.error('username: ' + username)

      // Test whether the user 'demo' enters the correct validation code
      data = JSON.parse(clientScriptOutputData);
      answer = data.answer;

      if (answer !== '123456') {
        logger.error('Authentication Failed !!')
        authState = FAILED;
      } else {
        logger.error('Authenticated !!')
        authState = SUCCESS;
      }
      ```

      Leave all other values as default.

      This server-side script tests that the user `demo` has entered `123456` as the verification code.

3. Add an authentication module:

   1. Select [icon: user, set=fa]Authentication > Modules, and add a module with the following settings:

      * Name : `VerificationCodeLevel1`

      * Type : `Scripted Module`

   2. In the authentication module, enable the option for client-side script, and select the following options:

      * Client-side Script : `Scripted Module - Client Side`

      * Server-side Script : `Scripted Module - Server Side`

      * Authentication Level : `1`

   3. Add the authentication module to an authentication chain:

      1. Select [icon: user, set=fa]Authentication > Chains, and add a chain called `VerificationCodeLevel1`.

      2. Add a module with the following settings:

         * Select Module : `VerificationCodeLevel1`

         * Select Criteria : `Required`

4. Test the setup:

   1. Log out of AM.

   2. Access the route:

      * For SSO, go to <https://ig.example.com:8080/home/pep-sso>.

      * For CDSSO, go to <https://ig.ext.com:8443/home/pep-cdsso>.

        If you have not previously authenticated to AM, the SingleSignOnFilter redirects the request to AM for authentication.

   3. Log in to AM as user `demo`, password `Ch4ng31t`.

      AM creates a session with the default authentication level `0`, and IG requests a policy decision.

      The updated policy requires authentication level `1`, which is higher than the AM session's current authentication level. AM issues a redirect with a `AuthenticateToServiceConditionAdvice` to authenticate at level `1`.

   4. In the session upgrade window, enter the verification code `123456`.

      AM upgrades the authentication level for the session to 1, and grants access to the sample application. If you try to access the sample application again in the same session, you don't need to provide the verification code.

### Increase authorization for a single transaction

Transactional authorization improves security by requiring a user to perform additional actions when trying to access a resource protected by an AM policy. For example, they must reauthenticate to an authentication module or respond to a push notification on their mobile device.

Performing the additional action successfully grants access to the protected resource, but only once. Additional attempts to access the resource require the user to perform the configured actions again.

This section builds on the example in [Step up the authentication level for an AM session](#stepup-sso-session), adding a simple authorization policy with a `Transaction` environment condition. Each time the user agent tries to access the protected resource, the user must reauthenticate to an authentication module by providing a verification code.

Before you start, configure AM as described in [Step up the authentication level for an AM session](#stepup-sso-session). The IG configuration is not changed.

1. In the AM admin UI, add a new environment condition:

   1. Select the policy set:

      * For SSO, select Authorization > Policy Sets > PEP-SSO.

      * For CDSSO, select Authorization > Policy Sets > PEP-CDSSO.

   2. In the IG policy, select Environments and add another environment condition:

      * `All of`

      * Type : `Transaction`

      * Authentication strategy : `Authenticate To Module`

      * Strategy specifier : `TxVerificationCodeLevel5`

2. Set up client-side and server-side scripts:

   1. Select [icon: code, set=fa]Scripts > New Script, and add the following client-side script:

      * Name : `Tx Scripted Module - Client Side`

      * Script Type : `Client-side Authentication`

        ```javascript
        autoSubmitDelay = 60000;

        function callback() {
            var parent = document.createElement("div");
            parent.className = "form-group";

            var label = document.createElement("label");
            label.className = "sr-only separator";
            label.setAttribute("for", "answer");
            label.innerText = "Verification Code";
            parent.appendChild(label);

            var input = document.createElement("input");
            input.className = "form-control input-lg";
            input.type = "text";
            input.placeholder = "Enter your TX code";
            input.name = "answer";
            input.id = "answer";
            input.value = "";
            input.oninput = function(event) {
                var element = document.getElementById("clientScriptOutputData");
                if (!element.value || element.value == "clientScriptOutputData") element.value = "{}";
                var json = JSON.parse(element.value);
                json["answer"] = event.target.value;
                element.value = JSON.stringify(json);
            };
            parent.appendChild(input);

            var fieldset = document.forms[0].getElementsByTagName("fieldset")[0];
            fieldset.prepend(parent);
        }

        if (document.readyState !== 'loading') {
            callback();
        } else {
            document.addEventListener("DOMContentLoaded", callback);
        }
        ```

        This client-side script adds a field to the AM form, in which the user is required to enter a TX code. The script formats the entered code as a JSON object, as required by the server-side script.

   2. Select [icon: code, set=fa]Scripts > New Script, and add the following server-side script:

      * Name : `Tx Scripted Module - Server Side`

      * Script Type : `Server-side Authentication`

        ```javascript
        username = 'demo'
        logger.error('username: ' + username)

        // Test whether the user 'demo' enters the correct validation code
        data = JSON.parse(clientScriptOutputData);
        answer = data.answer;

        if (answer !== '789') {
          logger.error('Authentication Failed !!')
          authState = FAILED;
        } else {
          logger.error('Authenticated !!')
          authState = SUCCESS;
        }
        ```

        This server-side script tests that the user `demo` has entered `789` as the verification code.

3. Add an authentication module:

   1. Select [icon: user, set=fa]Authentication > Modules, and add a module with the following settings:

      * Name : `TxVerificationCodeLevel5`

      * Type : `Scripted Module`

   2. In the authentication module, enable the option for client-side script, and select the following options:

      * Client-side Script : `Tx Scripted Module - Client Side`

      * Server-side Script : `Tx Scripted Module - Server Side`

      * Authentication Level : `5`

4. Test the setup:

   1. Log out of AM.

   2. Access your route:

      * For SSO, go to <http://ig.example.com:8080/home/pep-sso>.

      * For CDSSO, go to <https://ig.ext.com:8443/home/pep-cdsso>.

        If you have not previously authenticated to AM, the SingleSignOnFilter redirects the request to AM for authentication.

   3. Log in to AM as user `demo`, password `Ch4ng31t`.

      AM creates a session with the default authentication level `0`, and IG requests a policy decision.

   4. Enter the verification code `123456` to upgrade the authorization level for the session to `1`.

      The authentication module you configured for transactional authorization requires authentication level `5`, so AM issues a `TransactionConditionAdvice`.

   5. In the transaction upgrade window, enter the verification code `789`.

      AM upgrades the authentication level for this policy evaluation to `5`, and then returns a policy decision that grants a one-time access to the sample application. If you try to access the sample application again, you must enter the code again.
