PingOne Advanced Identity Cloud

Access tokens

Use this extension point to modify the key-value pairs in an OAuth 2.0 access token before PingOne Advanced Identity Cloud issues it.

This page demonstrates a simple script. For additional options, refer to the sample access token modification script. Advanced Identity Cloud uses the sample script as the default, commented OAuth 2.0 access token modification script.

Constraints

You can modify both client-side and server-side access tokens. You can also modify macaroons used in place of regular tokens.

PingOne Advanced Identity Cloud stores the modifications in client-side and server-side access tokens. When issuing modified access tokens, consider the following constraints:

  • Removing or changing native properties may render the access token unusable.

    PingOne Advanced Identity Cloud relies on native properties that it includes in the access token. If you remove or modify those properties, PingOne Advanced Identity Cloud considers the access token invalid. This can cause the OAuth 2.0 flows to break.

  • Modifying access tokens can significantly increase the size of the token.

    Adding key-value pairs to OAuth 2.0 access tokens affects the size of client-side JSON web tokens (JWT), or the size of server-side tokens, if enabled.

    Make sure the modified tokens fit within your client and user-agent size limits.

Learn more in Token storage.

Prepare the demonstration

Start by preparing the demonstration:

Sample script

The sample adds key-value pairs to the access token. It uses methods of the accessToken and identity bindings.

  1. Create the script.

    In the Advanced Identity Cloud admin UI, select Scripts > Auth Scripts > + New Script, and create a new OAuth2 Access Token Modification script.

  2. Name the script Demo access token modification.

  3. Replace the default JavaScript with the following and save your script:

    (function () {
      // Add a field next to the access token in the /oauth2/access_token response.
      accessToken.addExtraData('hello', 'world');
    
      // Add identity profile attribute values to the /oauth2/introspect response.
      accessToken.setField('mail', identity.getAttribute('mail'));
      accessToken.setField('phone', identity.getAttribute('telephoneNumber').toArray()[0]);
    
      // No return value is expected.
    }());

    The accessToken methods update the access token before PingOne Advanced Identity Cloud issues it.

    The identity methods get attribute values from the resource owner’s profile.

OAuth 2.0 client

The OAuth 2.0 client profile in this example overrides the OAuth 2.0 provider settings. This lets you test the script without affecting access tokens issued to other clients.

  1. Create a confidential OAuth 2.0 client account.

    In the Advanced Identity Cloud admin UI, select Applications > + Add Application, and create a new Web client with the following settings:

    Client ID

    myClient

    Client Secret

    forgerock

  2. Add the following settings in the client profile and save your work:

    Sign-in URLs

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

    Scopes

    access

  3. Override OAuth 2.0 provider settings for this client.

    Under Native Consoles > Access Management, select Realms > alpha > Applications > OAuth 2.0 > Clients > myClient, switch to the OAuth2 Provider Overrides tab, update the following settings and save your work:

    Enable OAuth2 Provider Overrides

    Enabled

    Access Token Modification Plugin Type

    SCRIPTED

    Access Token Modification Script

    Demo access token modification

Resource owner

An OAuth 2.0 client requests the access token on behalf of a resource owner.

  1. Create the OAuth 2.0 resource owner account.

    In the Advanced Identity Cloud admin UI, select Identities > Manage > Alpha Realm - Users > + New Alpha Realm - User and fill the required fields.

    Record the username and password.

  2. Update the following settings in the new user profile and save your work:

    Email Address

    user@example.com

    Telephone Number

    (555) 323-1234

Test the demonstration

After preparing the demonstration, test your work using HTTP calls to REST endpoints.

The demonstration uses the Authorization code grant flow:

  • The resource owner authenticates to obtain an SSO token.

  • The client relies on Implied Consent being enabled (default). It assumes the resource owner grants the client access.

  • The client requests the authorization code and exchanges it for an access token your script modified.

  • The client introspects the access token.

Follow these steps:

  1. Authenticate as the resource owner:

    curl \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'X-OpenAM-Username: <resource-owner-username>' \
    --header 'X-OpenAM-Password: <resource-owner-password>' \
    --header 'Accept-API-Version: resource=2.0, protocol=1.0' \
    'https://<tenant-env-fqdn>/am/json/realms/root/realms/alpha/authenticate'
    {"tokenId":"<resource-owner-tokenId>","successUrl":"/enduser/?realm=/alpha","realm":"/alpha"}
  2. Request the authorization code as the client:

    curl \
    --dump-header - \
    --request POST \
    --cookie '<session-cookie-name>=<resource-owner-tokenId>' \
    --data 'scope=access' \
    --data 'response_type=code' \
    --data 'client_id=myClient' \
    --data 'csrf=<resource-owner-tokenId>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    --data 'state=abc123' \
    --data 'decision=allow' \
    'https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/authorize'
    ...
    location: https://www.example.com:443/callback?code=<authorization-code>&iss=https%3A%2F%2F...
    ...
  3. Exchange the authorization code for an access token as the client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'grant_type=authorization_code' \
    --data 'code=<authorization-code>' \
    --data 'redirect_uri=https://www.example.com:443/callback' \
    'https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/access_token'
    {
      "access_token": "<access-token>",
      "refresh_token": "<refresh-token>",
      "scope": "access",
      "hello": "world",
      "token_type": "Bearer",
      "expires_in": 3599
    }

    The script added "hello": "world" alongside the access token in the /oauth2/access_token response.

  4. Introspect the access token as the client:

    curl \
    --request POST \
    --user 'myClient:forgerock' \
    --data 'token=qOshQEHOg2r-AU2kmJgBzfUEC5M' \
    'https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha/introspect'
    {
      "active": true,
      "scope": "access",
      "realm": "/alpha",
      "client_id": "myClient",
      "user_id": "014c54bd-6078-4639-8316-8ce0e7746fa4",
      "username": "014c54bd-6078-4639-8316-8ce0e7746fa4",
      "token_type": "Bearer",
      "exp": 1668597726,
      "sub": "014c54bd-6078-4639-8316-8ce0e7746fa4",
      "subname": "014c54bd-6078-4639-8316-8ce0e7746fa4",
      "iss": "https://<tenant-env-fqdn>/am/oauth2/realms/root/realms/alpha",
      "auth_level": 0,
      "authGrantId": "dNJ9r6jMA6yZ88nnho7f6KDCESk",
      "auditTrackingId": "3819034a-4294-4b56-94ea-8e6015869083-2607123",
      "mail": ["user@example.com"],
      "phone": "(555) 323-1234"
    }

    The script added "mail": ["user@example.com"] and "phone": "(555) 323-1234".

Use a validated script

Test your access token modification scripts as you did for the demonstration. After validating your script with OAuth 2.0 provider overrides in your test client, you can update the OAuth 2.0 provider configuration to use the script in one of the following ways:

  • Under Native Consoles > Access Management, select Realms > realm > Services > OAuth2 Provider, switch to the Plugins tab, edit the Access Token Modification Script, and save your work.

  • In the Advanced Identity Cloud admin UI, select Scripts > Auth Scripts > OAuth2 Access Token Modification Script, and replace the script content with your validated script.

Available objects

PingOne Advanced Identity Cloud injects the following objects into the execution context of an OAuth 2.0 access token modification script:

Binding Information

accessToken

The OAuth 2.0 access token.

For details, refer to AccessToken.

clientProperties

A map of properties configured in the client profile.

The map has the following keys:

clientId

The client identifier string

allowedGrantTypes

An array of grant types

allowedResponseTypes

An array of strings listing response types

allowedScopes

An array of strings listing scopes

customProperties

A map of any custom properties added to the client.

These properties can include lists or maps as sub-maps. For example, the script includes customMap[Key1]=Value1 as customMap > Key1 > Value1 in the object.

Under Native Consoles > Access Management, add custom properties to a client. Go to OAuth 2.0 > Clients > Client ID > Advanced, and update the Custom Properties field.

The map is null if PingOne Advanced Identity Cloud did not successfully identify the client.

httpClient

An HTTP client for making external HTTP requests.

identity

An identity PingOne Advanced Identity Cloud can access.

For details, refer to AMIdentity.

logger

Write a message to the PingOne Advanced Identity Cloud debug log. Always present in all extension scripts.

In Advanced Identity Cloud, this corresponds to the am-core log source.

Logger names use the format scripts.OAUTH2_ACCESS_TOKEN_MODIFICATION.<script UUID>.(<script name>).

Learn more about debug logs in Get audit and debug logs.

requestProperties

A map of the properties present in the request.

The map has the following keys:

requestUri

The URI as a string

realm

The realm as a string

requestParams

A map of request parameters and posted data, where each value is an array of parameters.

To mitigate the risk of reflection-type attacks, use OWASP best practices when handling these parameters. Refer to Unsafe use of Reflection.
requestHeaders

The value of the named request header. Returns a map of <String, List<String>> as a native JavaScript object, for example:

var ipAddress = requestProperties.requestHeaders["X-Forwarded-For"][0]

Header names are case-sensitive.

scriptName

The display name of the script.

scopes

An array of the requested scopes; for example, ["read", "transfer", "download"].

session

The user’s session object if the request contains a session cookie.

For details, refer to SSOToken.