---
title: Get an access token in a journey
description: This use case creates a service account access token for each authentication request, which can cause performance issues. Instead, Ping Identity recommends you use the service account openidm script binding to get the access token.
component: pingoneaic
page_id: pingoneaic:use-cases:use-case-access-token-for-journeys
canonical_url: https://docs.pingidentity.com/pingoneaic/use-cases/use-case-access-token-for-journeys.html
keywords: ["Use Case", "Journeys", "Scripts", "REST API", "Setup &amp; Configuration"]
section_ids:
  get-access-token-description: Description
  get-access-token-goals: Goals
  get-access-token-prereqs: Prerequisites
  get-access-token-tasks: Tasks
  get-access-token-task-1: "Task 1: Create ESVs"
  get-access-token-task-2: "Task 2: Create a script to get an access token"
  get-access-token-task-3: "Task 3: Create a journey to get an access token"
  get-access-token-validation: Validation
  get-access-token-validation-steps: Steps
  get-access-token-explore-further: Explore further
  get-access-token-reference-material: Reference material
  get-access-token-nodes-used: Nodes used
---

# Get an access token in a journey

|   |                                                                                                                                                                                                                                                                                                    |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | This use case creates a service account access token for each authentication request, which can cause performance issues. Instead, Ping Identity recommends you use the service account [openidm script binding](../am-scripting/next-generation-scripts.html#v2-openidm) to get the access token. |

## Description

Estimated time to complete: 25 minutes *(tooltip: This assumes you complete the prerequisites beforehand.)*

In this use case, create a script to get an access token using a service account. A service account lets you request access tokens for most Advanced Identity Cloud REST API endpoints. Then, create a simple journey with this script to prove you can successfully request an access token.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The script in this use case uses the `fr:idm:*` scope for access to `/openidm/*` API endpoints. If you want to get an access token for other Advanced Identity Cloud API endpoints, set up your [service account](../tenants/service-accounts.html#service-account-scopes) for the required scopes and update the scopes referenced in the script to match.Service accounts can only be used with Advanced Identity Cloud API endpoints; if you want to communicate with a third-party API, you'll need to use the standard [OAuth 2.0 client credential](../am-oauth2/oauth2-client-cred-grant.html) flow. |

### Goals

After completing this use case, you will know how to do the following:

* Get an access token to use in API calls in a [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/latest/scripted-decision.html) in Advanced Identity Cloud.

## Prerequisites

Before you start work on this use case, ensure you have these prerequisites:

* A basic understanding of:

  * Journeys and nodes

  * JavaScript

  * Service accounts

  * ESVs

* Access to your Advanced Identity Cloud development environment as a tenant administrator.

* A [service account](../tenants/service-accounts.html#create-a-new-service-account) that can grant the `fr:idm:*` scope to an access token.

  You'll need the service account ID and private key later when you create ESVs.

## Tasks

### Task 1: Create ESVs

1. In the Advanced Identity Cloud admin console, go to [icon: cog, set=fa]Tenant Settings > Global Settings > Environment Secrets & Variables.

2. Create the following ESVs:

   | ESV name                         | ESV type          | Description                                                                                                                                                                                                                                                                                                                                                                           |
   | -------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | `esv-tenant-env-fqdn`            | Variable (string) | Tenant FQDN (in the appropriate [FQDN format](../tenants/environments.html#tenant-environment-fqdns)); for example: `openam-mycompany-ew2.id.forgerock.io`                                                                                                                                                                                                                            |
   | `esv-service-account-id`         | Secret            | Service account ID; for example: `449d7e27-7889-47af-a736-83b6bbf97ec5`                                                                                                                                                                                                                                                                                                               |
   | `esv-service-account-privatekey` | Secret            | Service account private key; for example:```none
   {
     d: "RhpIZ32rNfkoVkQh3pt1me...rDkFL9nBWDOZvXQ2LsFEBc",
     dp: "RfrvtBH_NmzxS......IpJ1vYZS_J0cw",
     dq: "OVO8_yXFRHT...2VREB2b8f8xvIhv5jrQWQ",
     e: "AQAB",
     kty: "RSA",
     n: "5LoH3Fc8IdRg1...K4eUvMEJsjVvfRgzpWCDM0",
     p: "_wjzIYyYcQiNOZdV1Cp7...kjDw",
     q: "5ZeYq0C......6WOaiYw",
     qi: "Z9ECeon...q56tpl2Mu65yqlw",
   }
   ``` |

3. Apply the updates.

   Learn more about creating ESVs and applying updates in [Manage ESVs using the admin console](../tenants/esvs-manage-ui.html) .

### Task 2: Create a script to get an access token

1. Download the sample script: [getAccessToken.js](../_attachments/getAccessToken.js).

   > **Collapse: View script**
   >
   > ```javascript
   > /*
   >  * Copyright © 2024 - 2026 Ping Identity Corporation
   >  *
   >  * 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.
   > */
   >
   > var nodeConfig = {
   >   nodeName: "Get Access Token Demo",
   >   tenantFqdnEsv: "esv.tenant.env.fqdn",
   >   accountIdEsv: "esv.service.account.id",
   >   privateKeyEsv: "esv.service.account.privatekey",
   >   accessTokenStateField: "idmAccessToken",
   >   maxAttempts: 3,
   >   scope: "fr:idm:*",
   >   serviceAccountClientId: "service-account",
   >   jwtValiditySeconds: 10,
   > };
   >
   > var nodeLogger = {
   >   debug: function (message) {
   >     logger.message("***" + nodeConfig.nodeName + " " + message);
   >   },
   >   warning: function (message) {
   >     logger.warning("***" + nodeConfig.nodeName + " " + message);
   >   },
   >   error: function (message) {
   >     logger.error("***" + nodeConfig.nodeName + " " + message);
   >   },
   > };
   >
   > var nodeOutcomes = {
   >   SUCCESS: "Success",
   >   ERROR: "Error",
   > };
   >
   > var javaImports = JavaImporter(
   >   org.forgerock.openam.auth.node.api.Action,
   >   org.forgerock.json.jose.builders.JwtBuilderFactory,
   >   org.forgerock.json.jose.jwt.JwtClaimsSet,
   >   org.forgerock.json.jose.jws.JwsAlgorithm,
   >   org.forgerock.json.jose.jws.SignedJwt,
   >   org.forgerock.json.jose.jws.handlers.SecretRSASigningHandler,
   >   org.forgerock.json.jose.jwk.RsaJWK,
   >   javax.crypto.spec.SecretKeySpec,
   >   org.forgerock.secrets.SecretBuilder,
   >   org.forgerock.secrets.keys.SigningKey,
   >   java.time.temporal.ChronoUnit,
   >   java.time.Clock,
   >   java.util.UUID
   > );
   >
   > function getKeyFromJwk(issuer, jwk) {
   >   var privateKey = javaImports.RsaJWK.parse(jwk).toRSAPrivateKey();
   >
   >   var secretBuilder = new javaImports.SecretBuilder();
   >
   >   secretBuilder
   >     .secretKey(privateKey)
   >     .stableId(issuer)
   >     .expiresIn(
   >       5,
   >       javaImports.ChronoUnit.MINUTES,
   >       javaImports.Clock.systemUTC()
   >     );
   >   return new javaImports.SigningKey(secretBuilder);
   > }
   >
   > function getAssertionJwt(accountId, privateKey, audience, validity) {
   >   var signingHandler = new javaImports.SecretRSASigningHandler(
   >     getKeyFromJwk(accountId, privateKey)
   >   );
   >
   >   var iat = new Date().getTime();
   >   var exp = new Date(iat + validity * 1000);
   >
   >   var jwtClaims = new javaImports.JwtClaimsSet();
   >
   >   jwtClaims.setIssuer(accountId);
   >   jwtClaims.setSubject(accountId);
   >   jwtClaims.addAudience(audience);
   >   jwtClaims.setExpirationTime(exp);
   >   jwtClaims.setJwtId(javaImports.UUID.randomUUID());
   >
   >   var jwt = new javaImports.JwtBuilderFactory()
   >     .jws(signingHandler)
   >     .headers()
   >     .alg(javaImports.JwsAlgorithm.RS256)
   >     .done()
   >     .claims(jwtClaims)
   >     .build();
   >
   >   return jwt;
   > }
   >
   > function getAccessToken(accountId, privateKey, tenantFqdn, maxAttempts) {
   >   var response = null;
   >   var accessToken = null;
   >   var tokenEndpoint = "https://"
   >     .concat(tenantFqdn)
   >     .concat("/am/oauth2/access_token");
   >
   >   nodeLogger.debug("Getting Access Token from endpoint " + tokenEndpoint);
   >
   >   var assertionJwt = getAssertionJwt(
   >     accountId,
   >     privateKey,
   >     tokenEndpoint,
   >     nodeConfig.jwtValiditySeconds
   >   );
   >
   >   if (!assertionJwt) {
   >     nodeLogger.error("Error getting assertion JWT");
   >     return null;
   >   }
   >
   >   nodeLogger.debug("Got assertion JWT " + assertionJwt);
   >
   >   for (var attempt = 0; attempt < maxAttempts; attempt++) {
   >     nodeLogger.debug("Attempt " + (attempt + 1) + " of " + maxAttempts);
   >     try {
   >       var request = new org.forgerock.http.protocol.Request();
   >       request.setUri(tokenEndpoint);
   >       request.setMethod("POST");
   >       request
   >         .getHeaders()
   >         .add("Content-Type", "application/x-www-form-urlencoded");
   >
   >       var params = "grant_type="
   >         .concat(
   >           encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer")
   >         )
   >         .concat("&client_id=")
   >         .concat(encodeURIComponent(nodeConfig.serviceAccountClientId))
   >         .concat("&assertion=")
   >         .concat(encodeURIComponent(assertionJwt))
   >         .concat("&scope=")
   >         .concat(encodeURIComponent(nodeConfig.scope));
   >
   >       request.setEntity(params);
   >       response = httpClient.send(request).get();
   >       if (response) {
   >         break;
   >       }
   >     } catch (e) {
   >       nodeLogger.error(
   >         "Failure calling access token endpoint: " +
   >           tokenEndpoint +
   >           " exception:" +
   >           e
   >       );
   >     }
   >   }
   >
   >   if (!response) {
   >     nodeLogger.error("Bad response");
   >     return null;
   >   }
   >
   >   if (response.getStatus().getCode() !== 200) {
   >     nodeLogger.error(
   >       "Unable to acquire Access Token. HTTP Result: " + response.getStatus()
   >     );
   >     return null;
   >   }
   >
   >   try {
   >     var responseJson = response.getEntity().getString();
   >     nodeLogger.debug("Response content " + responseJson);
   >     var oauth2response = JSON.parse(responseJson);
   >     accessToken = oauth2response.access_token;
   >     nodeLogger.debug("Access Token acquired: " + accessToken);
   >     return accessToken;
   >   } catch (e) {
   >     nodeLogger.error("Error getting access token from response: " + e);
   >   }
   >
   >   return null;
   > }
   >
   > (function () {
   >   try {
   >     nodeLogger.debug("Node starting");
   >
   >     var accessToken = nodeState.get(nodeConfig.accessTokenStateField);
   >
   >     if (accessToken) {
   >       nodeLogger.debug("Access token already present: continuing");
   >       action = javaImports.Action.goTo(nodeOutcomes.SUCCESS).build();
   >       return;
   >     }
   >
   >     var tenantFqdn = systemEnv.getProperty(nodeConfig.tenantFqdnEsv);
   >     if (!tenantFqdn) {
   >       nodeLogger.error("Couldn't get FQDN from esv " + config.tenantFqdnEsv);
   >       action = javaImports.Action.goTo(nodeOutcomes.ERROR).build();
   >       return;
   >     }
   >
   >     var accountId = systemEnv.getProperty(nodeConfig.accountIdEsv);
   >     if (!accountId) {
   >       nodeLogger.error(
   >         "Couldn't get service account id from esv " + nodeConfig.accountIdEsv
   >       );
   >       action = javaImports.Action.goTo(nodeOutcomes.ERROR).build();
   >       return;
   >     }
   >
   >     var privateKey = systemEnv.getProperty(nodeConfig.privateKeyEsv);
   >     if (!privateKey) {
   >       nodeLogger.error(
   >         "Couldn't get private key from esv " + nodeConfig.privateKeyEsv
   >       );
   >       action = javaImports.Action.goTo(nodeOutcomes.ERROR).build();
   >       return;
   >     }
   >
   >     accessToken = getAccessToken(
   >       accountId,
   >       privateKey,
   >       tenantFqdn,
   >       nodeConfig.maxAttempts
   >     );
   >
   >     if (!accessToken) {
   >       nodeLogger.error("Failed to get access token");
   >       action = javaImports.Action.goTo(nodeOutcomes.ERROR).build();
   >       return;
   >     }
   >
   >     nodeLogger.debug("Success - adding token to transient state");
   >     nodeState.putTransient(nodeConfig.accessTokenStateField, accessToken);
   >     action = javaImports.Action.goTo(nodeOutcomes.SUCCESS).build();
   >   } catch (e) {
   >     nodeLogger.error("Exception encountered " + e);
   >     action = javaImports.Action.goTo(nodeOutcomes.ERROR).build();
   >     return;
   >   }
   > })();
   > ```

2. In the Advanced Identity Cloud admin console, go to [icon: code, set=material, size=inline] Scripts > Auth Scripts and click + New Script.

3. Select Journey Decision Node and click Next.

4. Select Legacy and click Next.

5. In the New Journey Decision Node Script window, enter the following details:

   | Field       | Value                                                                                         |
   | ----------- | --------------------------------------------------------------------------------------------- |
   | Name        | `Get access token`                                                                            |
   | Description | `Get an access token using a service account`                                                 |
   | JavaScript  | Replace the sample JavaScript with the contents of the downloaded `getAccessToken.js` script. |

6. Check the variables defined in the script and update as needed:

   ```javascript
   var nodeConfig = {
     nodeName: "Get Access Token Demo", (1)
     tenantFqdnEsv: "esv.tenant.env.fqdn", (2)
     accountIdEsv: "esv.service.account.id", (3)
     privateKeyEsv: "esv.service.account.privatekey", (4)
     accessTokenStateField: "idmAccessToken",
     maxAttempts: 3,
     scope: "fr:idm:*", (5)
     serviceAccountClientId: "service-account", (6)
     jwtValiditySeconds: 10,
   };
   ```

   |       |                                                                                                                                                                                                              |
   | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
   | **1** | The `nodeName` indicates the name of your journey for debugging purposes.                                                                                                                                    |
   | **2** | The `tenantFqdnEsv` contains the script reference to the `esv-tenant-env-fqdn` ESV.                                                                                                                          |
   | **3** | The `accountIdEsv` contains the script reference to the `esv-service-account-id` ESV.                                                                                                                        |
   | **4** | The `privateKeyEsv` contains the script reference to the `esv-service-account-privatekey` ESV.                                                                                                               |
   | **5** | The `scope` you chose when you set up your service account; this determines which API endpoints you can get an access token for.                                                                             |
   | **6** | The `serviceAccountClientId` must be set to `service-account` to use the built-in OAuth 2.0 public client for service accounts; otherwise, the JWT profile for OAuth 2.0 authorization grant flow will fail. |

7. Click Save and Close.

### Task 3: Create a journey to get an access token

1. In the Advanced Identity Cloud admin console, go to [icon: account_tree, set=material, size=inline] Journeys and click + New Journey.

2. In the New Journey window, enter the following details:

   | Field           | Value                                                    |
   | --------------- | -------------------------------------------------------- |
   | Name            | `Get Access Token Demo`                                  |
   | Identity Object | Alpha realm - Users `managed/alpha_user`                 |
   | Description     | `Journey to get an access token using a service account` |

3. Click Save. The journey editor displays.

4. In the journey editor, search for the `Scripted Decision` node and drag it onto the canvas.

5. Configure this node as follows:

   | Field    | Value                                      |
   | -------- | ------------------------------------------ |
   | Name     | `Get Access Token`                         |
   | Script   | `Get access token`                         |
   | Outcomes | Create two outcomes: `Success` and `Error` |

6. In the journey editor, search for the `Message Node` and drag two copies of it onto the canvas.

7. Select the first `Message Node` and configure it as follows:

   | Field   |       | Value                                |
   | ------- | ----- | ------------------------------------ |
   | Name    |       | `Success Message`                    |
   | Message | Key   | `en`                                 |
   |         | Value | `Access token successfully acquired` |

8. Select the second `Message Node` and configure it as follows:

   | Field   |       | Value                        |
   | ------- | ----- | ---------------------------- |
   | Name    |       | `Error Message`              |
   | Message | Key   | `en`                         |
   |         | Value | `Failed to get access token` |

9. Connect the nodes:

   ![Get access token journey](_images/use-case-get-access-token/get-access-token-journey.png)

   | Source node                                | Outcome path | Target node                                |
   | ------------------------------------------ | ------------ | ------------------------------------------ |
   | Start (person icon)                        | →            | Scripted Decision node(`Get Access Token`) |
   | Scripted Decision node(`Get Access Token`) | Success      | Message node(`Success Message`)            |
   |                                            | Error        | Message node(`Error Message`)              |
   | Message node(`Success Message`)            | True         | Success node                               |
   |                                            | False        | Success node                               |
   | Message node(`Error Message`)              | True         | Failure node                               |
   |                                            | False        | Failure node                               |

10. Click Save.

Check in

At this point, you:

|                                                                                       |
| ------------------------------------------------------------------------------------- |
| [icon: check, set=fa]Created ESVs for the tenant FQDN and service account details.    |
| [icon: check, set=fa]Created a script to get an access token using a service account. |
| [icon: check, set=fa]Created a simple journey to get an access token.                 |
|                                                                                       |

## Validation

Now that you have created a journey to get an access token, you are ready to validate it.

The journey runs the script to acquire an access token using the service account and ESVs you set up. If an access token is successfully acquired, the Success Message is shown.

|   |                                                                                                                                                                    |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | If you want to view the access token created during testing, you can enable [debug mode](../end-user/debug-enduser-journeys.html) in your development environment. |

### Steps

1. In the Advanced Identity Cloud admin console, go to [icon: account_tree, set=material, size=inline] Journeys and click on the `Get Access Token Demo` journey you just created.

2. In the Preview URL field, click [icon: copy, set=material, size=inline] and paste the URL into an incognito window.

   The script runs to get an access token, and if successful, the Success Message displays:

   ![Success message](_images/use-case-get-access-token/access-token-success.png)

   The Yes and No buttons shown are the default outcomes for a Message node; they are not relevant to this example and don't do anything further.

   If an access token is not acquired, the Error Message is shown instead (`Failed to get access token`).

## Explore further

### Reference material

| Reference                                                                                                                               | Description                                                                                    |
| --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| [Service accounts](../tenants/service-accounts.html)                                                                                    | Information about service accounts in Advanced Identity Cloud.                                 |
| [Authenticate to Advanced Identity Cloud REST API with access token](../developer-docs/authenticate-to-rest-api-with-access-token.html) | Learn how to authenticate to Advanced Identity Cloud REST API endpoints using an access token. |
| [ESVs](../tenants/esvs.html)                                                                                                            | Information about environment secrets and variables (ESVs).                                    |
| [Journeys](../journeys/journeys.html)                                                                                                   | Conceptual information on journeys and their purpose in Advanced Identity Cloud.               |
| [Journey nodes](../journeys/auth-nodes.html)                                                                                            | Learn about the configurable nodes Advanced Identity Cloud offers for use in journeys.         |
| [Scripted Decision node API](../am-scripting/scripting-api-node.html)                                                                   | Reference information for journey decision node scripts.                                       |

### Nodes used

|   |                                                                         |
| - | ----------------------------------------------------------------------- |
|   | The following nodes are listed in the order they appear in the journey. |

* [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/latest/scripted-decision.html)

* [Message node](https://docs.pingidentity.com/auth-node-ref/latest/message.html)

* [Success node](https://docs.pingidentity.com/auth-node-ref/latest/success.html)

* [Failure node](https://docs.pingidentity.com/auth-node-ref/latest/failure.html)
