---
title: Scope validation
description: Use this plugin to configure the OAuth2 provider to validate the set of requested scopes against the allowed scopes and, optionally, to modify the list of valid scopes.
component: pingam
version: 8.1
page_id: pingam:am-oauth2:plugins-scope-validation
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-oauth2/plugins-scope-validation.html
keywords: ["OAuth 2.0", "Customizations", "Plugins", "Authorization", "Java", "Scripting", "Scope"]
page_aliases: ["plugins-scope-validator.adoc", "oauth2-guide:plugins-scope-validation.adoc"]
section_ids:
  example_scope_validation_plugin: Example scope validation plugin
  config-scope-validation-plugin: Create a custom script
  configure-scope-validation-plugin: Configure AM to use the custom scope validation script
  create-oauth2-scope-validation-client: Create an OAuth2 client
  try-scope-validation-plugin: Try the script
---

# Scope validation

Use this plugin to configure the OAuth2 provider to validate the set of requested scopes against the allowed scopes and, optionally, to modify the list of valid scopes.

* Sample script

  [OAuth2 Validate Scope Script](../am-scripting/sample-scripts.html#oauth2-validate-scope-js) (Legacy)

* Script bindings

  * [Common bindings](../am-scripting/script-bindings.html)

  * [Scope validation scripting API](../am-scripting/scope-validation-api.html)

* Java interface

  `org.forgerock.oauth2.core.plugins.ScopeValidator`

  > **Collapse: Sample Java code**
  >
  > ```java
  > /*
  >  * Copyright 2021-2025 Ping Identity Corporation. All Rights Reserved
  >  *
  >  * This code is to be used exclusively in connection with Ping Identity
  >  * Corporation software or services. Ping Identity Corporation only offers
  >  * such software or services to legal entities who have entered into a
  >  * binding license agreement with Ping Identity Corporation.
  >  */
  >
  > package org.forgerock.openam.examples;
  >
  > import java.util.HashSet;
  > import java.util.Set;
  >
  > import org.forgerock.oauth2.core.ClientRegistration;
  > import org.forgerock.oauth2.core.OAuth2Request;
  > import org.forgerock.oauth2.core.exceptions.ServerException;
  > import org.forgerock.oauth2.core.plugins.ScopeValidator;
  >
  > /**
  >  * Custom implementation of the Scope Validator
  >  * plugin interface {@link org.forgerock.oauth2.core.plugins.ScopeValidator}
  >  *
  >  * <li>
  >  * The {@code validateAuthorizationScope} method
  >  * adds default scopes, or any allowed scopes provided.
  >  * </li>
  >  *
  >  * <li>
  >  * The {@code validateAccessTokenScope} method
  >  * adds default scopes, or any allowed scopes provided.
  >  * </li>
  >  *
  >  * <li>
  >  * The {@code validateRefreshTokenScope} method
  >  * adds the scopes from the access token,
  >  * or any requested scopes provided that are also in the access token scopes.
  >  * </li>
  >  *
  >  *  * <li>
  >  *  * The {@code validateBackChannelAuthorizationScope} method
  >  *  * adds default scopes, or any allowed scopes provided.
  >  *  * </li>
  >  *
  >  */
  > public class CustomScopeValidator implements ScopeValidator {
  >
  >     @Override
  >     public Set<String> validateAuthorizationScope(ClientRegistration clientRegistration, Set<String> scope,
  >             OAuth2Request oAuth2Request) throws ServerException {
  >
  >         if (scope == null || scope.isEmpty()) {
  >             return clientRegistration.getDefaultScopes();
  >         }
  >
  >         Set<String> scopes = new HashSet<String>(clientRegistration.getAllowedScopes());
  >         scopes.retainAll(scope);
  >         return scopes;
  >     }
  >
  >     @Override
  >     public Set<String> validateAccessTokenScope(ClientRegistration clientRegistration,
  >             Set<String> scope, OAuth2Request request) throws ServerException {
  >
  >         if (scope == null || scope.isEmpty()) {
  >             return clientRegistration.getDefaultScopes();
  >         }
  >
  >         Set<String> scopes = new HashSet<String>(clientRegistration.getAllowedScopes());
  >         scopes.retainAll(scope);
  >         return scopes;
  >     }
  >
  >     @Override
  >     public Set<String> validateRefreshTokenScope(ClientRegistration clientRegistration,
  >             Set<String> requestedScope, Set<String> tokenScope, OAuth2Request request) {
  >
  >         if (requestedScope == null || requestedScope.isEmpty()) {
  >             return tokenScope;
  >         }
  >
  >         Set<String> scopes = new HashSet<String>(tokenScope);
  >         scopes.retainAll(requestedScope);
  >         return scopes;
  >     }
  >
  >     @Override
  >     public Set<String> validateBackChannelAuthorizationScope(ClientRegistration clientRegistration,
  >             Set<String> requestedScopes, OAuth2Request request) throws ServerException {
  >
  >         if (requestedScopes == null || requestedScopes.isEmpty()) {
  >             return clientRegistration.getDefaultScopes();
  >         }
  >
  >         Set<String> scopes = new HashSet<>(clientRegistration.getAllowedScopes());
  >         scopes.retainAll(requestedScopes);
  >         return scopes;
  >     }
  > }
  > ```

The plugin comprises four functions or methods that let you customize the validation of scopes at the following endpoints:

| Function / Method                       | Endpoint                                        |
| --------------------------------------- | ----------------------------------------------- |
| `validateAuthorizationScope`            | `/authorize`                                    |
| `validateAccessTokenScope`              | `/authorize` and `/access_token`                |
| `validateRefreshTokenScope` (1)         | `/access_token` with `grant_type=refresh_token` |
| `validateBackChannelAuthorizationScope` | `/bc_authorize`                                 |

(1) To make sure the refresh token inherits the scopes currently granted to the access token, call `scopeValidatorHelper.inheritAccessTokenScopesOnRefresh()` from this method in your next-generation script.

## Example scope validation plugin

Follow these steps to implement a scope validation script that modifies the list of valid scopes.

1. [Create a custom script](#config-scope-validation-plugin)

2. [Configure AM to use the custom scope validation script](#configure-scope-validation-plugin)

3. [Create an OAuth2 client](#create-oauth2-scope-validation-client)

4. [Try the script](#try-scope-validation-plugin)

|   |                                                                                                                                                                              |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Learn about how to implement a *Java* scope validation plugin in [Configure AM to use a Java OAuth 2.0 plugin](customizing-oauth2-scopes.html#configure-java-oauth2-plugin). |

### Create a custom script

This example script adds a `customscope` to the requested scopes.

1. [Create a new](../am-scripting/manage-scripts-console.html#create-scripts-with-console) OAuth2 Validate Scope Script.

2. Name your script `Demo scope validation script`.

   You can create either a Legacy or a Next Generation script.

3. In the script window, add the following JavaScript:

   * Legacy

   * Next-generation

   ```javascript
   function validateScopes() {
     var frJava = JavaImporter(
       org.forgerock.oauth2.core.exceptions.InvalidScopeException
     )

     var scopes;
     if (requestedScopes) {
       scopes = new java.util.HashSet(allowedScopes);
       scopes.retainAll(requestedScopes);
       if (requestedScopes.size() > scopes.size()) {
         var invalidScopes = new java.util.HashSet(requestedScopes);
         invalidScopes.removeAll(allowedScopes);
         throw new frJava.InvalidScopeException('Unknown/invalid scope(s)');
       }
     } else {
       scopes = defaultScopes;
     }

     if (scopes) {
         // Validation succeeded. Add a custom scope.
         scopes.add('customscope')
         return scopes;
     } else {
         throw new frJava.InvalidScopeException('No scope requested and no default scope configured');
     }
   }

   function validateAuthorizationScope() {
     return validateScopes();
   }

   function validateAccessTokenScope() {
     return validateScopes();
   }

   function validateRefreshTokenScope() {
     return validateScopes();
   }

   function validateBackChannelAuthorizationScope() {
     return validateScopes();
   }
   ```

   ```javascript
   function validateScopes() {

       var scopes = [];

       if (!requestedScopes || requestedScopes.isEmpty()) {
           scopes = defaultScopes;
       } else {
           // Filter requestedScopes to only those found in allowedScopes
           for each (var requested in requestedScopes) {
               if (allowedScopes.contains(requested)) {
                   scopes.push(requested);
               }
           }

           // At least one scope was invalid if more scopes requested than allowed
           if (requestedScopes.size() > scopes.length) {
               // Find which specific scopes were invalid for the error log
               for each (var checkScope in requestedScopes) {
                   if (!allowedScopes.contains(checkScope)) {
                       logger.error("Invalid scope detected: " + checkScope);
                   }
               }
               logger.error("Unknown/invalid scope(s)");
           }
       }
       if (scopes) {
         // Validation succeeded. Add a custom scope.
         scopes.add('customscope')
       } else {
         logger.error("No scope requested and no default scope configured");
       }
       return scopes;
   }
   function validateAuthorizationScope() {
       return validateScopes();
   }

   function validateAccessTokenScope() {
       return validateScopes();
   }

   function validateRefreshTokenScope() {
       return validateScopes();
   }

   function validateBackChannelAuthorizationScope() {
       return validateScopes();
   }
   ```

   |   |                                                                                                                                                                                                                                                                                                                      |
   | - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | You can find information about the common bindings such as `logger` and `scriptName` in [Common bindings](../am-scripting/script-bindings.html).You can find information about the bindings specific to scope validation scripts in the [Scope validation scripting API](../am-scripting/scope-validation-api.html). |

4. Save your changes.

### Configure AM to use the custom scope validation script

Perform this task to set up the OAuth2 provider to use the scope validation script.

1. [Configure the provider](customizing-oauth2-scopes.html#configure-scripted-oauth2-plugin) and make sure the following properties are set:

   * Scope Validation Plugin Type to `SCRIPTED`.

   * Scope Validation Script to `Demo scope validation script`.

2. Save your changes.

### Create an OAuth2 client

Create and configure a client application to override the OAuth 2.0 provider settings in the authorization flow.

1. [Create an OAuth 2.0 client](oauth2-register-client.html) with the following values:

   * Client ID

     `myClient`

   * Client secret

     `mySecret`

   * Redirection URIs

     `https://www.example.com:443/callback`

   * Scope(s)

     `mail`

2. On the Advanced tab, add `Client Credentials` to the Grant Types, and save your changes.

3. Switch to the OAuth2 Provider Overrides tab and update the following settings:

   * Enable OAuth2 Provider Overrides

     Enabled

   * Scope Validation Plugin Type

     `SCRIPTED`

   * Scope Validation Script

     `Demo scope validation script`

4. Save your changes.

AM is now configured to use your custom scope validation script.

### Try the script

To try your custom script, use the [Client credentials grant](oauth2-client-cred-grant.html) flow.

1. Send a POST request to the [/oauth2/access\_token](oauth2-access_token-endpoint.html) endpoint, specifying the grant type as `client_credentials`, scope as `access`, and your client details.

   For example:

   ```bash
   $ curl \
   --request POST \
   --data "grant_type=client_credentials" \
   --data "client_id=myClient" \
   --data "client_secret=mySecret" \
   --data "scope=access" \
   "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/access_token"
   {
     "access_token": "<access-token>",
     "scope": "access",
     "token_type": "Bearer",
     "expires_in": 3599
   }
   ```

2. Call the [oauth2/tokeninfo](legacy-oauth2-endpoints.html#varlist-oauth2-tokeninfo-endpoint) endpoint to inspect the custom scope values. Include the access token value obtained in the previous request.

   For example:

   ```bash
   $ curl \
   "https://am.example.com:8443/am/oauth2/realms/root/realms/alpha/tokeninfo\
   ?access_token=<access-token>"
   {
     "access_token": "<access-token>",
     "access": "",
     "grant_type": "client_credentials",
     "auditTrackingId": "f9a8395d-1bac-4cba-8b09-8cc336dc49e2-6810",
     "scope": ["access", "customscope"],
     "realm": "/alpha",
     "token_type": "Bearer",
     "expires_in": 3583,
     "authGrantId": "l3355H89FDSWsfdKJmvWssGk_oE",
     "customscope": "",
     "client_id": "myClient"
   }
   ```

   Verify that the response contains both the requested scope and the additional scope, `customscope`.
