---
title: DS for AM CTS
description: Show how to replicate AM core token service (CTS) data and fail over when a DS server is unavailable.
component: pingds
version: 8.1
page_id: pingds:use-cases:cts
canonical_url: https://docs.pingidentity.com/pingds/8.1/use-cases/cts.html
revdate: 2026-01-27T13:21:24Z
keywords: ["CTS Store (Sessions &amp; Tokens)", "LDAP", "Use Case"]
section_ids:
  description: Description
  goals: Goals
  example_scenario: Example scenario
  prerequisites: Prerequisites
  knowledge: Knowledge
  actions: Actions
  tasks: Tasks
  task_1_prepare_for_installation: "Task 1: Prepare for installation"
  task_2_set_up_ds: "Task 2: Set up DS"
  task_3_set_up_tomcat: "Task 3: Set up Tomcat"
  task_4_set_up_am: "Task 4: Set up AM"
  task_5_create_a_test_user: "Task 5: Create a test user"
  validation: Validation
  access_am_as_the_test_user: Access AM as the test user
  test_cts_failover: Test CTS failover
  whats_next: What's next
  explore_further: Explore further
  related_use_cases: Related use cases
  reference_material: Reference material
---

# DS for AM CTS

Show how to replicate AM core token service (CTS) data and fail over when a DS server is unavailable.

## Description

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

AM uses DS to store CTS data, such as session tokens, data for SAML v2.0 and OAuth 2.0 applications, and push notifications.

Replicate the CTS data as you would any other directory data for availability, but realize AM applications are not necessarily built with DS eventual consistency in mind. For this reason, configure AM to use affinity load balancing when connecting to the DS CTS store. Affinity load balancing ensures each request for the same entry goes to the same DS server. If the DS server becomes unavailable, AM fails over to another DS server.

Suppose an AM application makes several AM calls in quick succession, and each call requires AM to retrieve a CTS entry from DS. Without affinity, if AM updates the CTS entry on one DS then reads it from another DS, it's possible replication won't have had time to replay the changes between the update and the subsequent read. The application could get a confusing response when it appears AM "forgets" the update.

With affinity, both the update and the read target the same DS server. The AM client application gets the expected response each time.

In this use case, you:

* Set up DS for AM CTS, configuration, and identity data.

* Set up and configure AM to use the DS service with affinity and failover.

* Show AM continues to work as expected when a DS server is unavailable.

## Goals

In completing this use case, you learn to:

* Set up DS and AM together.

* Configure affinity and failover for AM connections to DS.

* Replicate CTS data effectively while minimizing the impact on AM clients.

## Example scenario

As a directory service administrator, Pat plans to deploy directory services for AM CTS data.

Pat knows AM has a number of configuration options for CTS, but wants to clarify the basic deployment principles before tuning the service for their specific deployment.

Pat plans to show the AM administrators the basic approach, and then discuss additional options.

## Prerequisites

### Knowledge

Before you start:

* Make sure you are familiar with the command line on your operating system.

* If you're new to directory services, consider working through the examples to [learn LDAP](../getting-started/ldap.html) and to [learn replication](../getting-started/replication.html).

* If you're new to AM, consider working through the [AM evaluation tasks](https://docs.pingidentity.com/pingam/8.1/evaluation/preface.html).

### Actions

Before you start, download:

* The AM .war file

* An appropriate version of Apache Tomcat

* The DS .zip file

## Tasks

This sample deployment shows the steps to replicate CTS data on your computer. Use the same steps with geographically distributed computers or virtual machines for a real deployment.

![Sample deployment of AM with DS](../_images/cts-sample.png)

* Two AM servlets run in Apache Tomcat and serve HTTP requests from AM client applications.

* Two replicated DS servers provide storage for AM.

* Each AM servlet makes LDAP requests to DS for CTS data.

### Task 1: Prepare for installation

1. Make sure there's an FQDN for AM.

   The cookie domain for AM session cookies depends on the FQDN, because the browser uses it to connect to AM.

   This sample simulates DNS on your computer by updating the [hosts file](https://en.wikipedia.org/wiki/Hosts_\(file\)) with an alias for each DS server:

   ```none
   # Simulate DNS with an FQDN alias for the loopback address:
   127.0.0.1       am.example.com
   ```

   When deploying in a production environment, make sure you have properly configured the DNS.

2. Unpack the server files once for each server to install.

   This sample uses folder locations aligned with the hostnames:

   | Base path         | Description          |
   | ----------------- | -------------------- |
   | `/path/to/ds1`    | First DS server      |
   | `/path/to/ds2`    | Second DS server     |
   | `/path/to/tomcat` | Apache Tomcat server |

3. Determine the port numbers for the service.

   This sample uses different port numbers for each server because all the servers are on the same computer:

   | Sample server | Port numbers                                             |
   | ------------- | -------------------------------------------------------- |
   | `ds1`         | LDAP: 1389 LDAPS: 1636 Admin: 4444 Replication: 8989     |
   | `ds2`         | LDAP: 11389 LDAPS: 11636 Admin: 14444 Replication: 18989 |
   | Tomcat        | HTTPS: 8080                                              |

   When installing each DS server on a different host, use the same port numbers everywhere.

4. Set the `JAVA_HOME` environment variable to a supported JDK home if it isn't already set:

   ```console
   $ export JAVA_HOME=<supported-jdk-home>
   ```

5. Define how the DS servers trust DS server certificates.

   This sample uses a private PKI based on the deployment ID. You generate a deployment ID for all DS servers using the `dskeymgr` command:

   ```console
   $ /path/to/ds1/bin/dskeymgr \
   create-deployment-id \
   --deploymentIdPassword password
   <deployment-id>
   ```

   The deployment ID is a string. To use it, you must have the deployment ID password.

   Once you generate the ID, set a `DEPLOYMENT_ID` environment variable for use in other steps of this sample:

   ```console
   $ export DEPLOYMENT_ID=<deployment-id>
   ```

6. Make sure Tomcat and AM trust DS server certificates for secure LDAPS connections.

   This sample uses the private PKI based on the deployment ID you generated. Prepare a truststore with the DS CA certificate for Tomcat:

   ```console
   $ /path/to/ds1/bin/dskeymgr \
   export-ca-cert \
   --deploymentId $DEPLOYMENT_ID \
   --deploymentIdPassword password \
   --outputFile /path/to/ca-cert.pem
   $ keytool \
   -importcert \
   -trustcacerts \
   -alias ca-cert \
   -file /path/to/ca-cert.pem \
   -keystore /path/to/truststore \
   -storepass changeit \
   -storetype JKS \
   -noprompt
   $ export TRUSTSTORE=/path/to/truststore
   ```

### Task 2: Set up DS

These sample commands prepare DS servers for AM CTS, configuration, and identities. They depend on the `DEPLOYMENT_ID` environment variable you set.

1. Set up the first DS server:

   ```console
   $ /path/to/ds1/setup \
   --deploymentId $DEPLOYMENT_ID \
   --deploymentIdPassword password \
   --rootUserDN uid=admin \
   --rootUserPassword password \
   --monitorUserPassword password \
   --hostname localhost \
   --adminConnectorPort 4444 \
   --ldapPort 1389 \
   --enableStartTls \
   --ldapsPort 1636 \
   --replicationPort 8989 \
   --bootstrapReplicationServer localhost:8989 \
   --bootstrapReplicationServer localhost:18989 \
   --profile am-config \
   --set am-config/amConfigAdminPassword:5up35tr0ng \
   --profile am-cts \
   --set am-cts/amCtsAdminPassword:5up35tr0ng \
   --profile am-identity-store \
   --set am-identity-store/amIdentityStoreAdminPassword:5up35tr0ng \
   --acceptLicense \
   --start
   ```

2. Set up the second DS server:

   ```console
   $ /path/to/ds2/setup \
   --deploymentId $DEPLOYMENT_ID \
   --deploymentIdPassword password \
   --rootUserDN uid=admin \
   --rootUserPassword password \
   --monitorUserPassword password \
   --hostname localhost \
   --adminConnectorPort 14444 \
   --ldapPort 11389 \
   --enableStartTls \
   --ldapsPort 11636 \
   --replicationPort 18989 \
   --bootstrapReplicationServer localhost:8989 \
   --bootstrapReplicationServer localhost:18989 \
   --profile am-config \
   --set am-config/amConfigAdminPassword:5up35tr0ng \
   --profile am-cts \
   --set am-cts/amCtsAdminPassword:5up35tr0ng \
   --profile am-identity-store \
   --set am-identity-store/amIdentityStoreAdminPassword:5up35tr0ng \
   --acceptLicense \
   --start
   ```

At this point, both DS servers are running and replicating changes to each other.

### Task 3: Set up Tomcat

1. Update Tomcat settings for AM:

   This command uses the `TRUSTSTORE` environment variable you set:

   ```shell
   echo "export CATALINA_OPTS=\"\$CATALINA_OPTS \
   -Djavax.net.ssl.trustStore=${TRUSTSTORE} \
   -Djavax.net.ssl.trustStorePassword=changeit \
   -Djavax.net.ssl.trustStoreType=jks \
   -server \
   -Xmx2g \
   -XX:MetaspaceSize=256m \
   -XX:MaxMetaspaceSize=256m\"" > /path/to/tomcat/bin/setenv.sh
   ```

   In production, don't set passwords and other secrets in Java system properties. Learn more in [Hardening and security](../deployment-guide/plans.html#plan-security).

2. Make the Tomcat scripts executable:

   ```console
   $ chmod +x /path/to/tomcat/bin/*.sh
   ```

3. Start Tomcat:

   ```console
   $ /path/to/tomcat/bin/startup.sh
   ```

At this point, Tomcat is ready for you to set up AM.

### Task 4: Set up AM

These steps prepare AM to use DS with affinity load balancing and failover.

1. Copy the AM .war file to `/path/to/tomcat/webapps/am1.war` and `/path/to/tomcat/webapps/am2.war`.

2. Configure AM at <http://am.example.com:8080/am1> and <http://am.example.com:8080/am2>.

   Use the following configuration settings:

   | Setting                                                      | Choice                                                                                                                                                                                                                                                         |
   | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | Configuration Options                                        | Create New Configuration.                                                                                                                                                                                                                                      |
   | Server Settings > Default User Password                      | `Passw0rd`                                                                                                                                                                                                                                                     |
   | Server Settings > Server URL                                 | `http://am.example.com:8080`                                                                                                                                                                                                                                   |
   | Server Settings > Cookie Domain                              | `example.com`                                                                                                                                                                                                                                                  |
   | Server Settings > Platform Locale                            | `en_US`                                                                                                                                                                                                                                                        |
   | Server Settings > Configuration Directory                    | `/path/to/am1` or `/path/to/am2`                                                                                                                                                                                                                               |
   | Configuration Data Store Settings > Configuration Data Store | External DS                                                                                                                                                                                                                                                    |
   | Configuration Data Store Settings > SSL/TLS Enabled          | Enable                                                                                                                                                                                                                                                         |
   | Configuration Data Store Settings > Host Name                | `localhost`                                                                                                                                                                                                                                                    |
   | Configuration Data Store Settings > Port                     | `1636`                                                                                                                                                                                                                                                         |
   | Configuration Data Store Settings > Encryption Key           | Save the generated key (example: `w72dwbuhsLQzFNcUftA8eMCaw3a5ayhL`) from `am1` to use when configuring `am2`.                                                                                                                                                 |
   | Configuration Data Store Settings > Root Suffix              | `ou=am-config`                                                                                                                                                                                                                                                 |
   | Configuration Data Store Settings > Login ID                 | `uid=am-config,ou=admins,ou=am-config`                                                                                                                                                                                                                         |
   | Configuration Data Store Settings > Password                 | `5up35tr0ng`                                                                                                                                                                                                                                                   |
   | Configuration Data Store Settings > Server configuration     | New deployment (`am1`) or Additional server for existing deployment (`am2`)&#xA;&#xA;The am2 server uses the same stores as those of the existing deployment.&#xA;&#xA;This choice causes the configurator to skip to the Site Configuration settings for am2. |
   | User Data Store Settings > User Data Store Type              | ForgeRock Directory Services (DS)                                                                                                                                                                                                                              |
   | User Data Store Settings > SSL/TLS Enabled                   | Enable                                                                                                                                                                                                                                                         |
   | User Data Store Settings > Directory Name                    | `localhost`                                                                                                                                                                                                                                                    |
   | User Data Store Settings > Port                              | `1636`                                                                                                                                                                                                                                                         |
   | User Data Store Settings > Root Suffix                       | `ou=identities`                                                                                                                                                                                                                                                |
   | User Data Store Settings > Login ID                          | `uid=am-identity-bind-account,ou=admins,ou=identities`                                                                                                                                                                                                         |
   | User Data Store Settings > Password                          | `5up35tr0ng`                                                                                                                                                                                                                                                   |
   | Site Configuration                                           | No                                                                                                                                                                                                                                                             |

3. Configure the CTS store with affinity load balancing to both DS servers.

   On the `am1` servlet, make these configuration changes, which are shared with the `am2` servlet:

   1. Log in to the AM admin UI at <http://am.example.com/am1> as `amadmin` with `Passw0rd`.

   2. Browse to Configure > Server Defaults > CTS.

   3. Use the following CTS settings, saving changes before switching tabs:

      | Setting                                             | Choice                                                               |
      | --------------------------------------------------- | -------------------------------------------------------------------- |
      | CTS Token Store > Store Mode                        | External Token Store                                                 |
      | CTS Token Store > Root Suffix                       | `ou=famrecords,ou=openam-session,ou=tokens`                          |
      | External Store Configuration > SSL/TLS Enabled      | Enable                                                               |
      | External Store Configuration > Connection String(s) | `localhost:1636,localhost:11636`                                     |
      | External Store Configuration > Login Id             | `uid=openam_cts,ou=admins,ou=famrecords,ou=openam-session,ou=tokens` |
      | External Store Configuration > Password             | `5up35tr0ng`                                                         |
      | External Store Configuration > Affinity Enabled     | Enable                                                               |

4. Configure the identity store with affinity load balancing to both DS servers.

   In the `am1` admin UI, while connected as `amadmin`:

   1. Browse to Top Level Realm > Identity Stores > ds1 > Server Settings.

   2. Update the following identity settings:

      | Setting          | Choice                 |
      | ---------------- | ---------------------- |
      | LDAP Server      | Add `localhost:11636`. |
      | Affinity Enabled | Enable                 |
      | Affinty Level    | Bind                   |

   3. Save your changes.

5. Configure the configuration store to use both DS servers.

   In the `am1` admin UI, while connected as `amadmin`:

   1. Browse to Deployment > Servers.

   2. *For each AM servlet*:

      * Browse to *Server URL* > Directory Configuration > Server.

      * Add an entry for the second DS server and save the changes:

        | Setting         | Choice      |
        | --------------- | ----------- |
        | NAME            | `ds2`       |
        | HOST NAME       | `localhost` |
        | PORT NUMBER     | `11636`     |
        | CONNECTION TYPE | SSL         |

      * Save your changes.

6. Log out of the AM admin UI.

7. Restart Tomcat to take the configuration changes into account.

   Wait a moment for Tomcat to shut down cleanly before starting it again:

   ```console
   $ /path/to/tomcat/bin/shutdown.sh
   $ /path/to/tomcat/bin/startup.sh
   ```

At this point, AM is ready to use.

### Task 5: Create a test user

You will use this account for validation.

1. Log in to the AM admin UI at <http://am.example.com/am1> as `amadmin` with `Passw0rd`.

2. Browse to Top Level Realm > Identities and click + Add Identity.

3. Use the following settings for the test user:

   | Setting       | Choice                |
   | ------------- | --------------------- |
   | User ID       | `bjensen`             |
   | Password      | `hifalutin`           |
   | Email Address | `bjensen@example.com` |
   | First Name    | `Babs`                |
   | Last Name     | `Jensen`              |
   | Full Name     | `Barbara Jensen`      |

4. Log out of the AM admin UI.

## Validation

To validate your work, check:

* A user can log in to one AM servlet and access the other with the same session while all servers are up.

* The session is still honored when a CTS store is unavailable.

The following sections show how to do this in detail.

### Access AM as the test user

1. Log in to AM at <http://am.example.com/am1> as `bjensen` with password `hifalutin`.

   The AM UI displays the user profile page:

   ![Profile page for the test user](../_images/bjensen-am-profile.png)

2. Switch AM servlets by updating the URL in the browser address bar, replacing `am1` with `am2`.

   The AM UI displays the same user profile page again.

3. On the command line, find the associated CTS token in DS:

   ```console
   $ /path/to/ds1/bin/ldapsearch \
   --hostname localhost \
   --port 1636 \
   --useSsl \
   --trustStorePath "${TRUSTSTORE}" \
   --trustStoreType JKS \
   --trustStorePassword changeit \
   --bindDn uid=openam_cts,ou=admins,ou=famrecords,ou=openam-session,ou=tokens \
   --bindPassword 5up35tr0ng \
   --baseDn ou=famrecords,ou=openam-session,ou=tokens \
   "(coreTokenUserId=id=bjensen,ou=user,ou=am-config)" \
   coreTokenObject
   ```

   Output

   ```
   dn: coreTokenId=[.var]##<token-id>##,ou=famrecords,ou=openam-session,ou=tokens
   coreTokenObject: {"clientDomain":"ou=am-config","clientID":"id=bjensen,ou=user,ou=am-config","...":...}
   ```

   Notice the CTS does not reference the test user account by its DN, but instead by its AM universal ID.

   > **Collapse: Show sample core token object**
   >
   > ```json
   > {
   > "clientDomain": "ou=am-config",
   > "clientID": "id=bjensen,ou=user,ou=am-config",
   > "creationTimeInMillis": 1706087705386,
   > "listeners": {
   > "8f51ba31-a2e8-4f44-a998-91b411ffde3e": true,
   > "f0e6df25-2a9c-4be7-a5bb-1ae22c834190": true
   > },
   > "maxCachingTimeInMinutes": 3,
   > "maxIdleTimeInMinutes": 30,
   > "maxSessionTimeInMinutes": 120,
   > "restrictedTokensBySessionID": {},
   > "sessionEventURLs": {},
   > "sessionID": {
   > "encryptedString": "ecJSF_y5EMdaJhQ4oJ01JGiXAyU.*AAJTSQACMDEAAlNLABxraFNLaytaenFKMlBtYjNmelpBdG9JTUU3ZEE9AAR0eXBlAANDVFMAAlMxAAA.*"
   > },
   > "sessionProperties": {
   > "Locale": "en_GB",
   > "authInstant": "2024-01-24T09:15:05Z",
   > "Organization": "ou=am-config",
   > "UserProfile": "Required",
   > "Principals": "bjensen",
   > "successURL": "/am1/console",
   > "CharSet": "UTF-8",
   > "Service": "ldapService",
   > "Host": "127.0.0.1",
   > "FullLoginURL": "/am1/UI/Login?realm=%2F",
   > "AuthLevel": "0",
   > "clientType": "genericHTML",
   > "AMCtxId": "4cc3e651-f4eb-4bd6-9355-03b2b0abb45b-319",
   > "loginURL": "/am1/UI/Login",
   > "UserId": "bjensen",
   > "AuthType": "DataStore",
   > "sun.am.UniversalIdentifier": "id=bjensen,ou=user,ou=am-config",
   > "HostName": "127.0.0.1",
   > "amlbcookie": "01",
   > "Principal": "id=bjensen,ou=user,ou=am-config",
   > "UserToken": "bjensen"
   > },
   > "sessionState": "VALID",
   > "sessionType": "USER",
   > "timedOutTimeInSeconds": 0
   > }
   > ```

You have shown the test user session works for either AM servlet.

### Test CTS failover

1. Stop the first DS server to force AM to use the second DS server:

   ```console
   $ /path/to/ds1/bin/stop-ds
   ```

2. Verify you can still access both AM servlets as `bjensen`.

   For `am1` and `am2`, the AM UI displays the user profile page.

3. Start the first DS server and stop the second:

   ```console
   $ /path/to/ds1/bin/start-ds
   $ /path/to/ds2/bin/stop-ds
   ```

4. Verify again you can still access both AM servlets as `bjensen`.

   For `am1` and `am2`, the AM UI displays the user profile page.

You have demonstrated how AM can use DS as a CTS store with affinity load balancing and failover.

## What's next

After successfully showing the sample to AM administrators, Pat leads a discussion to review the tradeoffs they can choose to make for the production deployment. Some of the questions to discuss include the following:

* Do we back up CTS data?

  If CTS data is lost, users must authenticate again.

  If that's acceptable, then we won't back up CTS data, which is volatile and potentially large.

* Should there be a separate DS service for CTS data?

  CTS access patterns are very different from identity store access patterns. They cause DS to fill and empty its database cache in very different ways.

  In a high-volume deployment, it may make sense to split the data up.

* What AM features are in use?

  Could we have DS reap expired tokens (optional) instead of AM (default)?

AM administrators can bring their own questions to the discussion.

## Explore further

### Related use cases

* [Cross-region replication](cross-region-replication.html)

### Reference material

| Reference                                                                             | Description                                                                  |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| [Core Token Service (CTS)](https://docs.pingidentity.com/pingam/8.1/cts/preface.html) | In-depth information on setting up AM CTS with explanations of the tradeoffs |
| [Install DS for AM CTS](../install-guide/profile-am-cts.html)                         | Details about DS for CTS                                                     |
| [Install DS for AM configuration](../install-guide/profile-am-config.html)            | Details about DS for AM configuration                                        |
| [Install DS for platform identities](../install-guide/profile-am-idrepo.html)         | Details about DS for AM identities                                           |
| [Entry expiration](../config-guide/import-export.html#backend-ttl)                    | Settings for letting DS reap expired tokens                                  |
