PingGateway

JwkSetHandler

Expose cryptographic keys as a JWK set. Use this handler to reuse exposed keys for their assigned purpose in a downstream application.

Consider the following limitations:

  • When the public key isn’t available, the corresponding private key can’t be exposed.

    Don’t expose private keys as a JWK.
  • Keys in secure storage, such as a Hardware Security Module (HSM) or remote server, can’t be exposed.

You can find a description of how secrets are managed in About secrets.

You can find more information about JWKs and JWK Sets in JSON Web Key (JWK).

Usage

{
  "name": string,
  "type": "JwkSetHandler",
  "config": {
    "secretsProvider": SecretsProvider reference,
    "purposes": [ object, ... ],
    "exposePrivateSecrets": configuration expression<boolean>
  }
}
"secretsProvider": SecretsProvider reference, required

The SecretsProvider containing secrets to expose in the JwkSet.

"purposes": array of objects, required

One or more purposes for the JwkSet key.

{
  "purposes": [
    {
      "secretId": configuration expression<secret-id>,
      "keyUsage": configuration expression<enumeration>
      "jwkAlgorithm": configuration expression<string>
    },
    ...
  ]
}
"secretId": configuration expression<secret-id>, required

The secret ID of the key to be exposed in the JwkSet.

This secret ID must point to a CryptoKey.

"keyUsage": configuration expression<enumeration>, required

The allowed use of the key:

  • AGREE_KEY: Export the private key used in the key agreement protocol, for example, Diffie-Hellman.

  • ENCRYPT: Export the public key used to encrypt data.

  • DECRYPT: Export the private key used to decrypt data.

  • SIGN: Export the private key used to sign data.

  • VERIFY: Export the public key used to verify signature data.

  • WRAP_KEY: Export the public key used to encrypt (wrap) other keys.

  • UNWRAP_KEY: Export the private key used to decrypt (unwrap) other keys.

"jwkAlgorithm": configuration expression<string>, optional

The algorithm to include in the generated JWK alg parameter.

PingGateway validates the algorithm against the known possible values. PingGateway doesn’t communicate the actual algorithm used to generate the key.

Learn more about the alg parameter in RFC 7517, Section 4.4.

exposePrivateSecrets: configuration expression<boolean>, optional

A flag indicating whether to publish private keys in a JWK set. As a security safeguard, this property is false by default to prevent the accidental exposure of private keys.

  • true: Publish both public and private keys in the JWK set

  • false: Publish only public keys in the JWK set

Default: false

Example

This example uses a JwkSetHandler to show the public key for signature verification.

  1. Generate a key pair:

    $ keytool \
    -genkeypair \
    -alias test-cert \
    -keyalg RSA \
    -keystore /path/to/secrets/jwk-example.p12 \
    -storepass password \
    -storetype PKCS12 \
    -keypass password \
    -dname CN=PingGateway,O=PingIdentity.com
  2. Add the following route to PingGateway:

    Linux

    $HOME/.openig/config/routes/jwksethandler.json

    Windows

    %appdata%\OpenIG\config\routes\jwksethandler.json

    {
      "name": "jwksethandler",
      "condition": "${find(request.uri.path, '/jwksethandler')}",
      "heap": [
        {
          "name": "Base64EncodedSecretStore",
          "type": "Base64EncodedSecretStore",
          "config": {
            "secrets": {
              "keystore.secret.id": "cGFzc3dvcmQ="
            }
          }
        },
        {
          "name": "KeyStoreSecretStore",
          "type": "KeyStoreSecretStore",
          "config": {
            "file": "/path/to/secrets/jwk-example.p12",
            "storeType": "PKCS12",
            "storePasswordSecretId": "keystore.secret.id",
            "secretsProvider": "Base64EncodedSecretStore",
            "mappings": [
              {
                "secretId": "key.secret.id",
                "aliases": [
                  "test-cert"
                ]
              }
            ]
          }
        }
      ],
      "handler": {
        "type": "JwkSetHandler",
        "config": {
          "secretsProvider": "KeyStoreSecretStore",
          "purposes": [
            {
              "secretId": "key.secret.id",
              "keyUsage": "VERIFY"
            }
          ]
        }
      }
    }

    Notice the following features of the route:

    • The route matches requests to /jwksethandler.

    • The base64-encoded secret matches the keystore passphrase.

    • The KeyStoreSecretStore provides access to the key pair you generated.

    • The JwkSetHandler exposes the key in the result.

  3. Go to https://ig.example.com:8443/jwksethandler.

    The route displays the verification key as a JWK set, shown here with line breaks for readability:

    {
        "keys": [
            {
                "kty": "RSA",
                "kid": "test-cert",
                "use": "sig",
                "x5t": "Ngjv9zWaLLftSDQ69k0w_knvz1Y",
                "x5c": [
                    "MIIEBjCCAm6gAwIBAgIJAJUiimxs5xUDMA0GCSqGSIb3DQEBDAUAMDExGTAXBgNVBAoTEFBpbmdJZGVudGl0eS5jb20xFDASBgNVBAMTC1BpbmdHYXRld2F5MB4XDTI1MTEyMjE1NDg0N1oXDTI2MDIyMDE1NDg0N1owMTEZMBcGA1UEChMQUGluZ0lkZW50aXR5LmNvbTEUMBIGA1UEAxMLUGluZ0dhdGV3YXkwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCvvF2RDymFXLaqTvLFL6EtMM8Mm1DoVtGo+2HRj/DWMWutESxwYe/2wJc8/8PlGb1/mguuUvwdXOG1B/WVNep9mLsEv8NKSUJXTYBoINtRPH4fOVp3L+P3wgtiYhLcB0VU8RodBJyRW0zNexlRp1XSQVZDl4V/n/seFYgkos2RBqHpjPw7YUetUBpvnjkIuC6vsCYrgtUug5ivbwzbfhF7G59Vp4jmO2RdmfinjSxdWOaHtOKVVNUuNTgr74EsqKA6KCRlPTYQ8NUB6FCFkkvdOs7KGWQykPdi4kBbiUytTjXULjpwSuA/e5kDcHRXHJwcC5Plzg0M4n2e/nHt536NpGPFEyx9ObJrqkuqEX08ULzmuM29zjwjEzOLCbYuvvITUyqP4TZ1Z1BUjahyOhHTBoOA7vtRNMJBDgwqEWwljZ57k6hVmzMKApN+5z8fm4IlnDrZD+e2Icxuh7Y68K3ve9b/pvYhgxU7PK0JABhXHPMA1adQIOMrDUCs6PM6WQUCAwEAAaMhMB8wHQYDVR0OBBYEFOgeIbVe+Ly72gDnTPmDtMB2lrInMA0GCSqGSIb3DQEBDAUAA4IBgQBdQ0pobGEGf0lgAf5JYRwLH24c/0n1sN3qyzkqiuDw2MbQ1ZZOUFgOY9CSp6eSNuUnwz0/kpGF8KdgX6981IVrANz8gV0G306iK/n7qPqusppJIFbYlzPy/W/oYg0bqRIDyHH+4GMcZkK1yNY4gvN7898kIjYMro8o9j3d5d5egw9o6mmJCS/w6Gy3n/VoWL+stgQY7drLK3JuzweHFjNjRRF1M7VzvZjtjVEqAB187pejfvqjVuIbWjKUYLcFHM8HTy5xEoqpc5wARG1CyXSIMPySllnoO0acql5N5obHaMbudagGAR+gAZv/GgWIrnupm1RcUNd/MVa3z2IQjXW2UojFCD92cvTILs3wH90uSwFBo7437rKNt03LNRxaSfbs6e0IRNnGZtEOpOU8suD/mX/tB/xecgcaveENvn27kYyciaFARQ6NtICdll7xZ8yYj9jGquzpFJeAuEpfSqz2Tyosr2e0pg4KT2KI+61mL68JBAg7ohscuZzMjG8rjWg="
                ],
                "n": "r7xdkQ8phVy2qk7yxS-hLTDPDJtQ6FbRqPth0Y_w1jFrrREscGHv9sCXPP_D5Rm9f5oLrlL8HVzhtQf1lTXqfZi7BL_DSklCV02AaCDbUTx-Hzlady_j98ILYmIS3AdFVPEaHQSckVtMzXsZUadV0kFWQ5eFf5_7HhWIJKLNkQah6Yz8O2FHrVAab545CLgur7AmK4LVLoOYr28M234RexufVaeI5jtkXZn4p40sXVjmh7TilVTVLjU4K--BLKigOigkZT02EPDVAehQhZJL3TrOyhlkMpD3YuJAW4lMrU411C46cErgP3uZA3B0VxycHAuT5c4NDOJ9nv5x7ed-jaRjxRMsfTmya6pLqhF9PFC85rjNvc48IxMziwm2Lr7yE1Mqj-E2dWdQVI2ocjoR0waDgO77UTTCQQ4MKhFsJY2ee5OoVZszCgKTfuc_H5uCJZw62Q_ntiHMboe2OvCt73vW_6b2IYMVOzytCQAYVxzzANWnUCDjKw1ArOjzOlkF",
                "e": "AQAB"
            }
        ]
    }