---
title: Scripting API
description: AM provides the following functionality and artifacts for scripting:
component: pingam
version: 7.3
page_id: pingam:scripting-guide:scripting-api
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-scripting/scripting-api.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
keywords: ["Scripts", "OAuth 2.0"]
section_ids:
  property-substitution-scripts: Reference substituted properties in scripts
---

# Scripting API

AM provides the following functionality and artifacts for scripting:

* [Scripted decision node API](../authentication-guide/scripting-api-node.html)

  (*Authentication trees only*)

  Access data in request headers, shared state, and user session data.

* [Policy Condition Script API](../authorization-guide/scripted-policy-condition.html#scripting-api-policy)

  Access the authorization state data, the information pertaining a session, and the user's profile data in authorization policies.

* [Customize OAuth 2.0](../oauth2-guide/customizing-oauth2-scopes.html)

  Extend authorization server behavior with the OAuth 2.0 plugins:

  * **[Access token modification](../oauth2-guide/modifying-access-tokens-scripts.html)** Modify the key-value pairs contained within an OAuth 2.0 access token.

  * **[Authorize endpoint data provider](../oauth2-guide/plugins-auth-endpoint-data-provider.html)** Return additional data from an authorization request.

  * **[Scope evaluation](../oauth2-guide/plugins-scope-evaluator.html)** Evaluate and return an OAuth2 access token's scope information.

  * **[Scope validation](../oauth2-guide/plugins-scope-validator.html)** Customize the set of requested scopes for authorize, access token, refresh token and back channel authorize requests.

  * **[OIDC user info claims](../oauth2-guide/plugins-user-info-claims.html)** Map scopes to claims and data for OpenID Connect ID tokens.

* [Access HTTP services](scripting-api-global-http-client.html)

  Configure the parameters for the HTTP client object in any server-side script.

* [Debug logging](scripting-api-global-logger.html)

  Add debug logging to any server-side script.

* [Token exchange](../oauth2-guide/token-exchange.html)

  Add `may_act` claims to OAuth 2.0/OpenID Connect exchanged tokens.

* [Scripted module API](../authentication-guide/scripting-api-authn.html)

  (Deprecated: *Authentication chains only*)

  Access authentication state data, user profile data, request data, and information gathered by client-side scripts.

## Reference substituted properties in scripts

The `systemEnv` binding, available to all AM script types, provides the following methods shown with their Java signatures:

```java
String getProperty(String propertyName);
String getProperty(String propertyName, String defaultValue);
<T> T getProperty(String propertyName, String defaultValue, Class<T> returnType);
```

where:

* `propertyName` refers to a [configuration expression](../setup-guide/property-value-substitution.html#configuration-expressions) identifier without the ampersand and braces.

  The `propertyName` always starts with a prefix; for example, `script.my.variable`. The default prefix is `script.` To change the prefix in the AM admin UI, go to Configure > Global Services > Scripting > Secondary Configurations > *Script Type* > Secondary Configurations > Engine Configuration > Property Name Prefix, and set the prefix without the trailing `.`

  Make sure the `propertyName` is specific enough to distinguish it from all other configuration expressions.

* `defaultValue` is a default value to use when no configuration expression identifier matches `propertyName`.

  It must not be `null`.

* `returnType` is a fully qualified Java class name; one of the following types:

  * `String`

  * `Integer`

  * `Double`

  * `List`

  * `Map`

  * `Boolean`

The following [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/7.3/auth-node-scripted-decision.html) examples use the default property name prefix:

* JavaScript

* Groovy

```javascript
// Properties should get resolved (set in AM)
var email = systemEnv.getProperty('script.tree.decision.node.email');
var name = systemEnv.getProperty('script.tree.decision.node.hostname', 'defaultHostname');
var port = systemEnv.getProperty('script.tree.decision.node.port', '587', java.lang.Integer);
var double = systemEnv.getProperty('script.tree.decision.node.double', '2.0', java.lang.Double);
var hasPort = systemEnv.getProperty('script.tree.decision.node.hasPort', 'false', java.lang.Boolean);
var map = systemEnv.getProperty('script.tree.decision.node.map', '{"defaultKey":"defaultValue"}', java.util.Map);
var list = systemEnv.getProperty('script.tree.decision.node.list', 'defaultValue', java.util.List);

// Properties should get resolved to their defaults (not set in AM)
var defaultName = systemEnv.getProperty('script.tree.decision.node.hostname.unresolved', 'defaultHostname');
var defaultPort = systemEnv.getProperty('script.tree.decision.node.port.unresolved', '587', java.lang.Integer);
var defaultDouble = systemEnv.getProperty('script.tree.decision.node.double.unresolved', '2.0', java.lang.Double);
var defaultHasPort = systemEnv.getProperty('script.tree.decision.node.hasPort.unresolved', 'false', java.lang.Boolean);
var defaultMap = systemEnv.getProperty('script.tree.decision.node.map.unresolved', '{"defaultKey":"defaultValue"}', java.util.Map);
var defaultList = systemEnv.getProperty('script.tree.decision.node.list.unresolved', 'defaultFirstValue,defaultSecondValue', java.util.List);

// Assert all property values - set the appropriate outcome
if (email === 'test@example.com' && name === 'testHostname' && port === 25 && double === 1.0 && hasPort === true
    && map.get('testKey') == 'testValue' && list == '[testFirstValue, testSecondValue]'
    && defaultName === 'defaultHostname' && defaultPort === 587 && defaultDouble === 2.0 && defaultHasPort === false
    && defaultMap.get('defaultKey') == 'defaultValue' && defaultList == '[defaultFirstValue, defaultSecondValue]') {
outcome = 'true';
} else {
outcome = 'false';
}
```

```groovy
// Properties should get resolved (set in AM)
String email = systemEnv.getProperty('script.tree.decision.node.email');
String name = systemEnv.getProperty('script.tree.decision.node.hostname', 'defaultHostname');
Integer port = systemEnv.getProperty('script.tree.decision.node.port', '587', java.lang.Integer);
Double testDouble = systemEnv.getProperty('script.tree.decision.node.double', '2.0', java.lang.Double);
Boolean hasPort = systemEnv.getProperty('script.tree.decision.node.hasPort', 'false', java.lang.Boolean);
Map map = systemEnv.getProperty('script.tree.decision.node.map', '{\"defaultKey\":\"defaultValue\"}', java.util.Map);
List list = systemEnv.getProperty('script.tree.decision.node.list', 'defaultValue', java.util.List);

// Properties should get resolved to their defaults (not set in AM)
String defaultName = systemEnv.getProperty('script.tree.decision.node.hostname.unresolved', 'defaultHostname');
Integer defaultPort = systemEnv.getProperty('script.tree.decision.node.port.unresolved', '587', java.lang.Integer);
Double defaultDouble = systemEnv.getProperty('script.tree.decision.node.double.unresolved', '2.0', java.lang.Double);
Boolean defaultHasPort = systemEnv.getProperty('script.tree.decision.node.hasPort.unresolved', 'false', java.lang.Boolean);
Map defaultMap = systemEnv.getProperty('script.tree.decision.node.map.unresolved', '{\"defaultKey\":\"defaultValue\"}', java.util.Map);
List defaultList = systemEnv.getProperty('script.tree.decision.node.list.unresolved', 'defaultFirstValue,defaultSecondValue', java.util.List);

// Assert all property values - set the appropriate outcome
if (email.equals('test@example.com') && name.equals('testHostname') && port == 25 && testDouble == 1.0d && hasPort == true
    && defaultName.equals('defaultHostname') && defaultPort == 587 && defaultDouble == 2.0d && defaultHasPort == false
    && map.get('testKey').equals('testValue')
    && list.get(0).equals('testFirstValue') && list.get(1).equals('testSecondValue')
    && defaultMap.get('defaultKey').equals('defaultValue')
    && defaultList.get(0).equals('defaultFirstValue') && defaultList.get(1).equals('defaultSecondValue')) {

    outcome = 'true';
} else {
    outcome = 'false';
}
```
