---
title: KeyStoreSecretStore
description: Manages a secret store for cryptographic keys and certificates, based on a standard Java keystore.
component: pinggateway
version: 2026
page_id: pinggateway:reference:KeyStoreSecretStore
canonical_url: https://docs.pingidentity.com/pinggateway/2026/reference/KeyStoreSecretStore.html
revdate: 2026-02-18T12:00:00Z
section_ids:
  KeyStoreSecretStore-usage: Usage
  KeyStoreSecretStore-properties: Properties
  KeyStoreSecretStore-file: file
  KeyStoreSecretStore-storeType: storeType
  KeyStoreSecretStore-storePasswordSecretId: storePasswordSecretId
  KeyStoreSecretStore-entryPasswordSecretId: entryPasswordSecretId
  KeyStoreSecretStore-secretsProvider: secretsProvider
  KeyStoreSecretStore-mappings: mappings
  KeyStoreSecretStore-leaseExpiry: leaseExpiry
  KeyStoreSecretStore-securityProvider: securityProvider
  KeyStoreSecretStore-autoRefresh: autoRefresh
  KeyStoreSecretStore-log: Log level
  KeyStoreSecretStore-example: Examples
  passwords_passphrases_and_api_keys: Passwords, passphrases, and API keys
  verification_keys: Verification keys
  KeyStoreSecretStore-moreinfo: More information
---

# KeyStoreSecretStore

Manages a secret store for cryptographic keys and certificates, based on a standard Java keystore.

|   |                                                                                                                        |
| - | ---------------------------------------------------------------------------------------------------------------------- |
|   | Legacy keystore types such as JKS and JCEKS are supported but aren't secure. Consider using the PKCS#12 keystore type. |

The secrets provider queries the KeyStoreSecretStore for a named secret, identified by a secret ID and a stable ID, corresponding to the `secret-id`/`aliases` mapping. The KeyStoreSecretStore returns a secret that exactly matches the name, and whose purpose matches the secret ID and any purpose constraints.

The secrets provider builds the secret, checking that the secret's constraints are met, and returns a unique secret. If the secret's constraints aren't met, the secrets provider cannot build the secret and the secret query fails.

Learn how PingGateway manages secrets in [About secrets](../security-guide/keys.html#about-secrets).

## Usage

```none
{
  "name": string,
  "type": "KeyStoreSecretStore",
  "config": {
    "file": configuration expression<string>,
    "storeType": configuration expression<string>,
    "storePasswordSecretId": configuration expression<string>,
    "entryPasswordSecretId": configuration expression<string>,
    "secretsProvider": SecretsProvider reference,
    "mappings": [ {
      "secretId": configuration expression<secret-id>,
      // Use aliases or aliasesMatching, not both:
      "aliases": array of configuration expression<string>,
      "aliasesMatching": [ string, …​ ]
    }, …​ ],
    "leaseExpiry": configuration expression<duration>,
    "securityProvider": configuration expression<string>,
    "autoRefresh": {
      "enabled": configuration expression<boolean>,
      "executor": ScheduledExecutorService reference
    }
  }
}
```

## Properties

### file

`"file"`: *configuration expression<[string](preface.html#definition-string)>, required*

The path to the keystore file.

### storeType

`"storeType"`: *configuration expression<[string](preface.html#definition-string)>, optional*

The keystore type.

Default: PKCS12

### storePasswordSecretId

`"storePasswordSecretId"`: *configuration expression<[secret-id](preface.html#definition-secretid)>, optional*

The secret ID of the password to access the keystore.

This secret ID must point to a [GenericSecret](../security-guide/keys.html#secret-types).

PingGateway searches for the value of the password until it finds it, first locally, then in parent routes, then in `config.json`.

To create a store password, add a file containing the password. The filename must correspond to the secret ID. The file content must contain only the password with no trailing spaces or carriage returns.

Default: None; the keystore isn't password-protected

### entryPasswordSecretId

`"entryPasswordSecretId"`: *configuration expression<[secret-id](preface.html#definition-secretid)>, optional*

The secret ID of the password to access entries in the keystore.

This secret ID must point to a [GenericSecret](../security-guide/keys.html#secret-types).

To create an entry password, add a file containing the password. The filename must correspond to the secret ID. The file content must contain only the password with no trailing spaces or carriage returns.

When this property is used, the password must be the same for all entries in the keystore. If the keystore uses different passwords for entries, `entryPasswordSecretId` doesn't work.

Default: The value of [storePasswordSecretId](#KeyStoreSecretStore-storePasswordSecretId)

### secretsProvider

`"secretsProvider"`: *SecretsProvider [reference](preface.html#definition-reference), required*

The [SecretsProvider](SecretsProvider.html) to query for the keystore password and key entry password.

### mappings

`"mappings"`: *array of [objects](preface.html#definition-object), required*

One or more mappings of one secret ID to one or more aliases.

Some keystores, such as a global Java truststore, can contain hundreds of valid certificates. Use this property to map multiple aliases to a secret ID without listing them all in the mapping.

The secret store uses the mappings as follows:

* When the secret is used to create signatures or encrypt values, the secret store uses the *active secret*, the first alias in the list.

* When the secret is used to verify signatures or decrypt data, the secret store tries all the mapped aliases in the list, starting with the first. It stops when it finds a secret that can successfully verify the signature or decrypt the data.

- `"secretId"`: *configuration expression<[secret-id](preface.html#definition-secretid)>, required*

  The secret ID of the key.

* `"aliases"`: *array of configuration expression<[strings](preface.html#definition-string)>, required if `aliasesMatching` isn't used*

  One or more key aliases. Named aliases are mapped to the secret ID.

  Use `aliases` or `aliasesMatching` but not both.

  The following example maps the named aliases to the named secret IDs:

  ```none
  "mappings": [
    {
      "secretId": "id.key.for.signing.jwt",
      "aliases": [ "signingkeyalias", "anothersigningkeyalias" ]
    },
    {
      "secretId": "id.key.for.encrypting.jwt",
      "aliases": ["encryptionkeyalias"]
    }
  ]
  ```

- `"aliasesMatching"`: *array of <[strings](preface.html#definition-string)>, required if `aliases` isn't used*

  One or more regular expressions to match key aliases. Aliases that match the expressions are mapped to the secret ID.

  Use `aliases` or `aliasesMatching` but not both.

  The following example maps aliases that match the regular expression `.*` to the named secret ID:

  ```none
  "mappings": [
    {
      "secretId": "id.key.for.signing.jwt",
      "aliasesMatching": [".*"]
    }
  ]
  ```

### leaseExpiry

`"leaseExpiry"`: *configuration expression<[duration](preface.html#definition-duration)>, optional*

The amount of time that secrets produced by this store can be cached before they must be refreshed.

If the duration is `zero` or `unlimited`, PingGateway issues a warning and uses the default value.

Default: 5 minutes

### securityProvider

`"securityProvider"`: *configuration expression<[string](preface.html#definition-string)>, optional*

Java security provider to use when loading the keystore.

For example, the name of a security provider in the `java.security` configuration file for the JVM.

Default: use the default security provider for the JVM

### autoRefresh

`"autoRefresh"`: *[object](preface.html#definition-object), optional*

Automatically reload the KeyStoreSecretStore when the keystore is edited or deleted.

* `enabled`: *configuration expression<[boolean](preface.html#definition-boolean)>, optional*

  Flag to enable or disable automatic reload:

  * `true`: Enable

  * `false`: Disable

  Default: `true`

- `"executor"`: *ScheduledExecutorService [reference](preface.html#definition-reference), optional*

  A [ScheduledExecutorService](ScheduledExecutorService.html) to monitor the keystore.

  Default: The default ScheduledExecutorService in the heap

## Log level

To facilitate debugging secrets for the KeyStoreSecretStore, in `logback.xml` add a logger defined by the fully qualified package name of the KeyStoreSecretStore. The following line in `logback.xml` sets the log level to `ALL`:

```xml
<logger name="org.forgerock.secrets.keystore" level="ALL" />
```

## Examples

### Passwords, passphrases, and API keys

You can store passwords, passphrases, and API keys in JCEKS and PKCS12 keystores using the Java `keytool` command. This feature is limited to Java software.

The following example uses the Java `keytool -importpass` command to store an API key:

```console
$ keytool \
-importpass \
-alias my-client-password \
-keystore /path/to/secrets/keystore \
-storepass:file /path/to/secrets/keystore.pin \
Enter the password to be stored:
Re-enter password:
```

Use a KeyStoreSecretStore to set the secret ID for the password, passphrase, or API key. The following example gets the password to authenticate to a third-party service from the keystore:

```json
{
  "heap": [
    {
      "name": "ClientPasswordSecretStore",
      "type": "KeyStoreSecretStore",
      "config": {
        "file": "/path/to/secrets/keystore",
        "storePasswordSecretId": "keystore.pin",
        "secretsProvider": {
          "type": "FileSystemSecretStore",
          "config": {
            "directory": "/path/to/secrets/",
            "format": "PLAIN"
          }
        },
        "mappings": [
          {
            "secretId": "client.password.secret.id",
            "aliases": [
              "my-client-password"
            ]
          }
        ]
      }
    },
    {
      "name": "Client of third-party service",
      "type": "Chain",
      "config": {
        "filters": [
          {
            "type": "HttpBasicAuthenticationClientFilter",
            "config": {
              "username": "my-client",
              "passwordSecretId": "client.password.secret.id",
              "secretsProvider": "ClientPasswordSecretStore"
            }
          }
        ],
        "handler": "ClientHandler"
      }
    }
  ]
}
```

### Verification keys

This example gets the keys to validate a signed access token from a keystore:

```none
"accessTokenResolver": {
  "type": "StatelessAccessTokenResolver",
  "config": {
    "secretsProvider": {
      "type": "KeyStoreSecretStore",
      "config": {
        "file": "IG_keystore.p12",
        "storeType": "PKCS12",
        "storePasswordSecretId": "keystore.secret.id",
        "entryPasswordSecretId": "keystore.secret.id",
        "mappings": [{
          "secretId": "verification.secret.id",
          "aliases": [ "verification.key.1", "verification.key.2" ]
        }]
      },
      "issuer": "https://am.example.com:8888/am/oauth2",
      "verificationSecretId": "verification.secret.id"
    }
  }
}
```

The JWT signature is validated as follows:

* If the JWT contains a `kid` with a mapped value, for example `verification.key.1`:

  * The secrets provider queries the KeyStoreSecretStore for a named secret with the secret ID `verification.secret.id` and the stable ID `verification.key.1`.

  * Because the KeyStoreSecretStore contains that mapping, the KeyStoreSecretStore returns a named secret.

  * The StatelessAccessTokenResolver tries to validate the JWT signature with the named secret. If it fails, the token is considered as invalid.

* If the JWT contains a `kid` with an unmapped value, for example, `verification.key.3`:

  * The secrets provider queries the KeyStoreSecretStore for a named secret with the secret ID `verification.secret.id` and the stable ID `verification.key.3`.

  * Because the KeyStoreSecretStore doesn't contain that mapping, named secret resolution fails. PingGateway tries valid secret resolution in the same way as when the JWT doesn't contain a `kid`.

* If the JWT doesn't contain a `kid`:

  * The secrets provider queries the KeyStoreSecretStore for all valid secrets, whose alias is mapped to the secret ID `verification.secret.id`. There are two valid secrets, with aliases `verification.key.1` and `verification.key.2`.

  * The StatelessAccessTokenResolver first tries to verify the signature with `verification.key.1`. If that fails, it tries `verification.key.2`.

  * If neither of the valid secrets can verify the signature, the token is considered as invalid.

## More information

[org.forgerock.secrets.keystore.KeyStoreSecretStore](../_attachments/apidocs/org/forgerock/secrets/keystore/KeyStoreSecretStore.html)

[org.forgerock.openig.secrets.KeyStoreSecretStoreHeaplet](../_attachments/apidocs/org/forgerock/openig/secrets/KeyStoreSecretStoreHeaplet.html)
