Skip to content
Connect2id

Key store configuration

1. Key usage contexts and key store modes

The Connect2id server uses cryptographic keys to secure issued tokens and other objects. The keys are organised into two independently configured and managed contexts:

  • OpenID provider / OAuth 2.0 authorisation server — A JSON Web Key (JWK) set for securing tokens and other objects in this context.

  • OpenID Federation — A separate JWK set for signing federation entity statements. Not required when federation is disabled.

Since Connect2id server 17.0, each context can use one of three key store modes:

Dynamic Static PKCS#11 (HSM) + static
  • Enables online generation, rotation, revocation, and archival of server keys
  • Keys are stored encrypted in the database
  • Keys are supplied as configured JWK set
  • No database storage is used
  • Selected signing keys are held in an HSM
  • Supplemented by a configured static JWK set
  • No database storage is used

The legacy static key configuration from server versions 1.x–16.x remains supported. To retain existing keys while enabling online key management, see migration to dynamic key storage.

The key store configuration is located in:

WEB-INF/keyStore.properties

Any property in this file can be overridden with a Java system property, using a -D argument at JVM startup:

-DkeyStore.encJWK=eyJrdHkiOiJvY3QiLCJ1c2UiOiJlbmMiLCJraWQiOiJrSUtPIiwiayI6IlNhX1pKbHlBamxBWDkxUTA5MFM0TkEiLCJpYXQiOjE3MzQ5Njk4Mzl9

See the external configuration guide for how to load configuration properties from environment variables, local files and other sources.

2. Dynamic mode

This is the default key store mode. For a new deployment, the initial server JWK sets are automatically generated. When the key store web API is enabled, keys can be generated, rotated, revoked and archived online.

In dynamic mode, the only required configuration is an encryption key to secure the private and secret key material stored in the database. All other configuration properties are optional.

keyStore.encJWK

128 or 256-bit AES key for encrypting the stored private key material. Required, unless the Connect2id server is configured with static JWK sets and / or a PKCS#11 (HSM) store. The key must be a JWK of type oct (octet sequence key), with use (key use) enc (encryption) and an optional kid (key ID). The JSON string may be additionally BASE64URL encoded, to prevent character escape issues in shell environments.

Use the provided generator to create a key store encryption key.

Example encryption JWK, BASE64URL-encoded:

keyStore.encJWK=eyJrdHkiOiJvY3QiLCJ1c2UiOiJlbmMiLCJraWQiOiJrSUtPIiwiayI6IlNhX1pKbHlBamxBWDkxUTA5MFM0TkEiLCJpYXQiOjE3MzQ5Njk4Mzl9

When specified, this configuration property overrides any encryption key in the optional WEB-INF/keyStoreEncJWK.json file.

The Connect2id server comes with a demo keyStoreEncJWK.json:

{
  "kty" : "oct",
  "use" : "enc",
  "k"   : "BuSbZycIAbLy9mrFlxGbwg"
}

For production, replace the demo key with a key generated for your deployment, either in this file or through keyStore.encJWK.

keyStore.apiAccessTokenSHA256

The access token for the key store web API, represented by its SHA-256 hash (in hexadecimal format). The hash is a measure to prevent accidental leakage of the token through configuration files, logs, etc. The token is of type Bearer, non-expiring and must contain at least 32 random alphanumeric characters to make brute force guessing impractical. If not specified the web API is disabled.

Additional access tokens, for token roll-over or other needs, can be configured by appending a dot (.) with a unique label to the property name, e.g. as keyStore.apiAccessTokenSHA256.1=abc....

The hash for a token with value ztucZS1ZyFKgh0tUEruUtiSTXhnexmd6:

keyStore.apiAccessTokenSHA256=cca68b8b82bcf0b96cb826199429e50cd95a042f8e8891d1ac56ab135d096633

keyStore.defaultRSAKeySize

The default size of new generated RSA JWKs. The supported sizes are 2048, 3072 and 4096 bits. The default value is 2048.

keyStore.defaultRSAKeySize=2048

keyStore.generateIfEmpty.{op|federation}

When true, automatically generates the required JWK set if the specified context (op for OpenID provider, federation for OpenID Federation) is empty. The default value is true (enabled).

keyStore.generateIfEmpty.op=true
keyStore.generateIfEmpty.federation=true

keyStore.generateIfEmptyParams.{op|federation}

Parameters for automatically generating a JWK set when the specified context is empty and keyStore.generateIfEmpty is true. Since v20.2.

The value is a comma-separated list of name:value pairs. Whitespace around commas and colons is ignored.

Supported parameters for the OpenID provider (op) context:

  • no_ec:true – Do not generate EC keys.
  • no_ec_secp256k1:true – Do not generate secp256k1 EC keys.
  • no_eddsa:true – Do not generate EdDSA keys.

RSA keys are always generated for the OpenID provider context. Their size is controlled by keyStore.defaultRSAKeySize. By default, no generation parameters are specified.

Supported parameters for the OpenID Federation (federation) context:

  • rsa:[size] – Generate an RSA key with the specified size. Supported sizes are 2048, 3072 and 4096 bits.
  • ec:P-256 – Generate an EC key with the P-256 curve.
  • eddsa:Ed25519 – Generate an EdDSA key with the Ed25519 curve.

If EC and / or EdDSA parameters are specified without an RSA parameter, no RSA key is generated for the OpenID Federation context. The default value is rsa:2048.

keyStore.generateIfEmptyParams.op=
keyStore.generateIfEmptyParams.federation=rsa:2048

keyStore.importIfEmpty.{op|federation}

JWK set to import into the key store if the specified context (op for OpenID provider, federation for OpenID Federation) is empty. The JSON string may also be BASE64URL-encoded to avoid character escaping issues in shell environments. The default value is none.

This property is intended for migration from a legacy or static key configuration, or from another OpenID provider server. The imported JWK set must include the private and secret key material required by the server.

Use keyStore.importExp to limit the import window.

Example import of a JWK set for the OpenID provider context:

keyStore.importIfEmpty.op=eyJrZXlzIjpbeyJwIjoiOFhBZnBxVnlvVTVRdVZsaXFZbjgzc1...

Example import of a JWK set for the OpenID Federation context:

keyStore.importIfEmpty.federation=eyJrZXlzIjpbeyJwIjoiODRDWkllVnNFcjFNTkpQN3...

keyStore.importExp

Time, in seconds since the Unix epoch, after which configured JWK sets will no longer be imported. The value must be no more than 24 hours ahead of the current time when the server starts.

This property applies to both JWK set contexts. It prevents an accidental reimport after the import window if an imported JWK set is later revoked.

Example expiration at 23:59:59 UTC on 31 December 2024:

keyStore.importExp=1735689599

keyStore.jwkSetCacheLifetime

Controls the local caching of JWK sets retrieved from the key store. The cache lifetime is specified in seconds. Zero or negative disables caching. Must not exceed 600 seconds (10 minutes). The default value is 60 seconds (1 minute).

keyStore.jwkSetCacheLifetime=60

3. Static mode

The server keys are statically configured. Key rotation and revocation are performed by updating the configured JWK set. This mode is equivalent to the legacy key configuration in Connect2id server releases 1.x to 16.x.

keyStore.staticJWKSet.{op|federation}

Static JWK set for the specified context (op for OpenID provider, federation for OpenID Federation). The JSON string may also be BASE64URL-encoded to avoid character escaping issues in shell environments. The default value is none.

When a static JWK set is specified for a context, the key store web API operations for key rotation and revocation are disabled for that context.

Use the provided generator to:

  • Create a new static JWK set.
  • Generate new keys for rollover and prepend them to an existing static JWK set.

Example static JWK set for the OpenID provider context:

keyStore.staticJWKSet.op=eyJrZXlzIjpbeyJwIjoiOFhBZnBxVnlvVTVRdVZsaXFZbjgzc1...

Example static JWK set for the OpenID Federation context:

keyStore.staticJWKSet.federation=eyJrZXlzIjpbeyJwIjoiODRDWkllVnNFcjFNTkpQN3...

Key selection and rollover

When signing or encrypting a token, the Connect2id server selects the first JWK in the set that matches the required algorithm and key use. Keys with X.509 certificates follow additional selection rules based on certificate validity.

To roll over to new keys, place them before the old keys in the JWK set:

{
  "keys": [
    { ... new key ... },
    { ... new key ... },
    { ... old key ... },
    { ... old key ... }
  ]
}

Retain old signing keys for as long as previously issued tokens need to remain verifiable. Their public keys will continue to be published. If the private signing material is no longer needed, the old keys can be retained as public-only JWKs.

Retain old private decryption keys for as long as objects encrypted with the corresponding public keys still need to be decrypted.

Permanent keys

The following permanent keys, identified by their kid (key ID), are not intended to be rotated:

  • hmac – Protects session identifiers, authorisation codes, identifier-based access tokens and PAR URIs.
  • refresh-token-encrypt – Protects self-contained refresh tokens.
  • subject-encrypt – Encrypts pairwise subject identifiers.

Preserve these keys when updating the JWK set. Changing them invalidates the identifiers or tokens protected with the previous keys, or changes the pairwise subject identifiers issued to clients.

4. PKCS#11 (HSM) + static mode

Selected signing keys are loaded from a PKCS#11 compliant key store (HSM) and the rest are statically configured. Check the HSM guide for the
supported key types and how to generate them on the device.

keyStore.pkcs11.{op|federation}.enable

Enables / disables PKCS#11 (HSM) support for the specified context (op for OpenID provider, federation for OpenID Federation). The default value is false (disabled).

To enable PKCS#11 for the OpenID provider context:

keyStore.pkcs11.op.enable=true

To enable PKCS#11 for the OpenID Federation context:

keyStore.pkcs11.federation.enable=true

keyStore.pkcs11.{op|federation}.configFile

The location of the Sun PKCS#11 provider configuration for the specified context (op for OpenID provider, federation for OpenID Federation). The configuration can be alternatively passed inline as a string. The string may also be BASE64URL-encoded to avoid character escaping issues in shell environments.

The PKCS#11 provider configuration specifies the driver to load for the HSM device, a slot number for it (as multiple HSM devices may be attached), and other attributes. These are explained in the Java PKCS#11 Reference Guide. The manual of your HSM device should also provide information.

To use the sample PKCS#11 configuration file:

keyStore.pkcs11.op.configFile=/WEB-INF/hsm.cfg

The sample PKCS#11 configuration file content:

name = NitroKeyHSM
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
slotListIndex = 0
attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
  CKA_SIGN = true
}

Passing the content of the sample PKCS#11 configuration file as a string:

keyStore.pkcs11.op.configFile=bmFtZSA9IE5pdHJvS2V5SFNNCmxpYnJhcnkgPSAvdXNyL2xpYi94ODZfNjQtbGludXgtZ251L29wZW5zYy1wa2NzMTEuc28Kc2xvdExpc3RJbmRleCA9IDEKYXR0cmlidXRlcygqLENLT19QUklWQVRFX0tFWSxDS0tfUlNBKSA9IHsKICBDS0FfU0lHTiA9IHRydWUKfQ

keyStore.pkcs11.{op|federation}.password

The password (PIN) required to unlock the HSM for the specified context (op for OpenID provider, federation for OpenID Federation).

Example password:

keyStore.pkcs11.op.password=648219

keyStore.pkcs11.{op|federation}.keyIDs

Optional list of identifiers (aliases) of PKCS#11 keys to load from the HSM for the specified context (op for OpenID provider, federation for OpenID Federation 1.0). If omitted or blank all recognised and supported keys will be loaded.

Example list of four key IDs to load:

keyStore.pkcs11.op.keyIDs.1=rsa-sign-1
keyStore.pkcs11.op.keyIDs.2=rsa-sign-2
keyStore.pkcs11.op.keyIDs.3=ec-sign-1
keyStore.pkcs11.op.keyIDs.4=ec-sign-2

keyStore.staticJWKSet.{op|federation}

Static JWK set to complement the PKCS#11 keys for the specified context (op for OpenID provider, federation for OpenID Federation). The JSON string may be additionally BASE64URL encoded, to prevent character escape issues in shell environments. The default value is none.

Example static JWK set for the OpenID provider context:

keyStore.staticJWKSet.op=eyJrZXlzIjpbeyJwIjoiOFhBZnBxVnlvVTVRdVZsaXFZbjgzc1...

5. Legacy configuration

The static key configuration properties from Connect2id server versions 1.x - 16.x remain supported.

jose.jwkSet

Static JWK set for the OpenID provider context. The JSON string may also be BASE64URL-encoded to avoid character escaping issues in shell environments.

The legacy WEB-INF/jwkSet.json file for setting the JWK set also remains supported and is overridden by this property.

Deprecated in v17.0, use keyStore.staticJWKSet.op instead.

jose.jwkSet=eyJrZXlzIjpbeyJwIjoiOFhBZnBxVnlvVTVRdVZsaXFZbjgzc1...

jose.federation.jwkSet

Static JWK set for the OpenID Federation context. The JSON string may also be BASE64URL-encoded to avoid character escaping issues in shell environments.

The legacy WEB-INF/federationJWKSet.json file for setting the JWK set also remains supported and is overridden by this property.

Deprecated in v17.0, use keyStore.staticJWKSet.federation instead.

jose.federation.jwkSet=eyJrZXlzIjpbeyJwIjoiODRDWkllVnNFcjFNTkpQN3...

pkcs11.enable

Deprecated in v17.0, use keyStore.pkcs11.op.enable instead.

pkcs11.configFile

Deprecated in v17.0, use keyStore.pkcs11.op.configFile instead.

pkcs11.password

Deprecated in v17.0, use keyStore.pkcs11.op.password instead.

pkcs11.keyIDs.*

Deprecated in v17.0, use keyStore.pkcs11.op.keyIDs.* instead.

6. Offline key generation

Connect2id provides a generator for server keys, available as a standalone executable JAR and as a library:

Run jwks-gen.jar without arguments to print its usage and available options:

java -jar jwks-gen.jar

Key store encryption JWK

Generate a new AES JWK for keyStore.encJWK, which encrypts the private and secret key material stored in the database:

java -jar jwks-gen.jar key-store jwk.json

To generate a new JWK with BASE64URL-encoded output:

java -jar jwks-gen.jar key-store -b64 jwk.json.b64

OpenID provider JWK set

Generate a new JWK set for the keyStore.staticJWKSet.op configuration property:

java -jar jwks-gen.jar op jwkSet.json

Sample console output:

JWKs generator for Connect2id software

[1] Generated new signing RSA 2048 bit key with ID 2MEj
[2] Generated new signing EC P-256 key with ID u20W
[3] Generated new signing EC P-384 key with ID EiN4
[4] Generated new signing EC P-521 key with ID lI36
[5] Generated new signing EC secp256k1 key with ID Cu0m
[6] Generated new signing Ed25519 key with ID WNkY
[7] Generated new encryption RSA 2048 bit key with ID 2e8T
[8] Generated new encryption EC P-256 key with ID 9Ica
[9] Generated new encryption EC P-384 key with ID a1Gi
[10] Generated new encryption EC P-521 key with ID Tm9r
[11] Generated new symmetric encryption 128 bit key with ID 78pg
[12] Generated new HMAC SHA 256 bit key with ID hmac
[13] Generated new subject encryption AES SIV 256 bit key with ID subject-encrypt
[14] Generated new refresh token encryption AES SIV 256 bit key with ID refresh-token-encrypt

To generate a new JWK set with BASE64URL-encoded output:

java -jar jwks-gen.jar op -b64 jwkSet.json.b64

For key rollover, generate new keys and prepend them to an existing static OpenID provider JWK set:

java -jar jwks-gen.jar op oldJWKSet.json newJWKSet.json

The existing keys, including the permanent keys, are retained. If oldJWKSet.json is missing a required permanent key, the generator creates and appends it. This is useful when upgrading to a Connect2id server release that introduces a new permanent key type.

The generator can include a self-signed X.509 certificate (x5c) for each generated public key. It can also skip the generation of EC, EdDSA or encryption keys. These options are useful for deployments that require a particular public JWK set layout, for example providers of external MFA for Microsoft Entra.

OpenID Federation JWK set

Generate a new BASE64URL-encoded JWK set containing a single 2048-bit RSA key for the keyStore.staticJWKSet.federation configuration property:

java -jar jwks-gen.jar federation -b64 jwkSet.json.b64

For key rollover, generate a new 2048-bit RSA key and prepend it to an existing federation JWK set:

java -jar jwks-gen.jar federation oldJWKSet.json newJWKSet.json

The generator also supports RSA key sizes of 3072 and 4096 bits, EC keys and EdDSA keys for federation use.

7. Retaining public JWKs for signature verification

A static JWK set may include public-only JWKs, without private key parameters. This allows a deployment to retain previously used signing keys for signature verification after removing their private key material.

For the OpenID provider context, the Connect2id server publishes these keys at the jwks.json endpoint. Clients and resource servers can use them to verify tokens signed with the corresponding private keys.

For the OpenID Federation context, public-only JWKs are included in issued Entity Configurations, allowing federation participants to verify entity statements signed with previously used keys.

8. PKIX / X.509 certificates

The public keys in a static JWK set may be furnished with X.509 certificates. An X.509 certificate enables client applications and resource servers to perform PKIX validation of the signing key for an issued JWT (ID token, self-contained access token, etc).

A certificate is added to a JWK in the x5c parameter. The parameter can include either the client certificate or a certificate chain (partial or complete).

When the Connect2id server publishes a JWK at the jwks.json endpoint the x5c parameter is always included when present. The certificate will also appear in the x5c header parameter of JWTs signed with its private key, unless the Connect2id server is configured otherwise:

When signing JWTs with a certificate-based JWK the Connect2id server will always select a JWK with an active certificate according to its not-before and not-after attributes. The selection will be biased towards the farthest expiring JWK to ensure optimal roll-over. If no active JWK is found the Connect2id server will log an SE2000 error and use the most recent expired certificate.

[main] ERROR MAIN - [SE2000] No signing RSA key with active (nbf < now < exp) X.509 certificate, using the first available. Add new key(s)!

Guarantees:

  • The Connect2id server will always use a signing JWK with an active X.509 certificate (nbf < now < exp), if such is present in the configured JWK set.

  • The Connect2id server will always use a signing JWK with an X.509 certificate when at least one is present for the key type (e.g. RSA) and key use (signing), ignoring any plain JWKs.

These guarantees also apply to keys stored in a HSM, as those keys by rule must be provisioned with an X.509 certificate.

Notes:

  • The Connect2id server will not perform PKIX validation of the X.509 certificate in a configured JWK.

  • Including an x5c header in JWTs can easily end up multiplying the size of the issued tokens.

9. Hardware Security Module (HSM)

As explained in the PKCS#11 + static mode, the Connect2id server can load keys from a PKCS#11 compliant
HSM to sign ID tokens and self-contained (JWT) access tokens.

Key generation on the HSM

The HSM must be provisioned with the required keys before they can be used by the Connect2id server.

  • For signing tokens with an RSA key, provision at least one RSA key with a size of 2048, 3072 or 4096 bits.

  • For signing tokens with an EC key, provision at least one EC key with curve P-256 (for JWS algorithm ES256), P-384 (for ES384) and / or P-521 (for ES512).

  • Every private key must be paired with an X.509 certificate (also stored on the HSM). The certificate can be signed by a CA or self-signed. Its not-before and not-after attributes delimit the time window during which the Connect2id server will use the private key for signing, as explained in the JWKs with certificates section.

  • When rotating an HSM-based key, the certificate validity windows of the old and the new key must overlap, so the Connect2id server can seamlessly roll-over from an expiring key to the next.

  • Every pairing of a private key and its X.509 certificate must be given a unique CKA_ID (identifier), also called “alias” in the Java KeyStore API. This identifier will become the kid (key ID) parameter of the JWK.

  • HSM must be able to keep up with the signing rate of the Connect2id server deployment. If the HSM signing throughput is exceeded the token signing will slow-down or fail, resulting in server timeouts or HTTP 500 errors.

Loading, merging and publishing of PKCS#11 keys

  • The Connect2id server will load from the HSM only those keys that it can use for RSA and ECDSA signing, as explained above, and ignore any other key types on the HSM.

  • The keys loaded from the HSM will be prepended to the configured static JWK set and published together at the jwks.json endpoint. The X.509 certificates of the PKCS#11 keys will be included in the JWK x5c parameter.

  • If the Connect2id server deployment is new (never issued tokens before) there should be no signing JWKs in the static JWK set that match the type and use of a key loaded from the HSM. For example, if the deployment is going to use an RSA HSM key, make sure the static JWK set has no JWK with "kty":"RSA" and "use":"sig". This should be done to avoid the publishing of static keys that will not be used.

  • If an existing Connect2id server deployment is switching to an HSM, keep the configured static JWK set just as it is.

PKCS#11 key selection guarantees

The Connect2id server applies to PKCS#11 keys the exact same key selection as for JWKs with X.509 certificates. What does this mean for existing deployments that plan to switch to an HSM?

  • If the deployment is using plain JWKs or JWKs with X.509 certificates, the Connect2id server can seamlessly roll-over to the JWKs loaded from an HSM.

  • A seamless roll-over (revert) from HSM-loaded JWKs to JWKs with certificates is also possible.

Debugging HSM issues

The Connect2id server logs the PKCS#11 keys loaded from the HSM device. Ignored keys will not appear in the log.

[KS0154] Key store mode for OP JWK set context: PKCS11_WITH_STATIC
[KS0160] Key store PKCS#11 enabled for OP JWK set: true
[KS0161] Key store PKCS#11 OP configuration file: /WEB-INF/hsm.cfg
[KS0162] Key store PKCS#11 OP password configured: true
[KS0163] Key store PKCS#11 OP key IDs to load: all
[SE1006] Loaded PKCS#11 provider SunPKCS11-NitroKeyHSM
[SE1007] Loaded PKCS#11 key store with 1 entries
[SE1009] Extracted JWK set with 1 keys from PKCS#11 key store SunPKCS11-NitroKeyHSM
[KS0164] Key store loaded PKCS#11 op JWK set:
[SE1008] JWK set:
[SE3000] [1] JWK type=RSA id=c2id-rsa-1 private=true use=sig size=2048 x5c=true pkcs#11=true thumbprint=Ft3-NA3jvcrnBu2_ZXV_nP4pcXtvK_i8MMd19woqwfI nbf=2024-12-18T18:02:48Z exp=2025-12-18T18:02:48Z
[SE1010] Assuming signature key use for RSA PKCS#11 JWK with ID c2id-rsa-1
[KS0157] Key store static OP JWK set:
[SE1008] JWK set:
[SE3000] [1] JWK type=EC id=c6kW private=true use=sig size=256 x5c=false pkcs#11=false thumbprint=ko4gUhJozvmjqFQYMU4PicL0uYQj7P2TvublrZN71YQ 
[SE3000] [2] JWK type=EC id=ogJz private=true use=sig size=384 x5c=false pkcs#11=false thumbprint=ZUeuqUPa3tQWT48E0-IzGTKYdF0UZX-euxPM2jUdKes 
[SE3000] [3] JWK type=EC id=JgQ6 private=true use=sig size=521 x5c=false pkcs#11=false thumbprint=MrYieuuepjrdA0rmulZZSPxUjVgN6osEouiROKKMiiA 
[SE3000] [4] JWK type=EC id=WtjM private=true use=sig size=256 x5c=false pkcs#11=false thumbprint=Fj_KAGkRQbS8x3AxQ2dngEvYNcUKZkYQkvN78F4s8ME 
[SE3000] [5] JWK type=OKP id=klr5 private=true use=sig size=256 x5c=false pkcs#11=false thumbprint=C4qsmT3lNmmOM8uhL5Wbt7bOA4YxoNe6Z3uqXvfTHdw 
[SE3000] [6] JWK type=RSA id=hlQj private=true use=enc size=2048 x5c=false pkcs#11=false thumbprint=jDt3TYMCus_aYct0FLOE-sqgvphGZtmOMxR_gWJBscg 
[SE3000] [7] JWK type=EC id=VArh private=true use=enc size=256 x5c=false pkcs#11=false thumbprint=iG1tTOt9ecWxqRjS2-Kfg_vLVUWHi0jehimXmBS0Hyc 
[SE3000] [8] JWK type=EC id=5uTk private=true use=enc size=384 x5c=false pkcs#11=false thumbprint=vhyKJBYD-JywtG_s56_sEbOZfY_AcFN5LuLmaJwy0b8 
[SE3000] [9] JWK type=EC id=iRYG private=true use=enc size=521 x5c=false pkcs#11=false thumbprint=ESyQLHvnilAUSEct52q_SnnHpRlOLnakS12I5yAbHfU 
[SE3000] [10] JWK type=oct id=Gdti use=enc size=128 x5c=false pkcs#11=false thumbprint=88CDlcqnV3ABZDMI9UZ3N81881MfpkjohOo4UyL-g18 
[SE3000] [11] JWK type=oct id=hmac use=sig size=256 x5c=false pkcs#11=false thumbprint=Fm7zaUubUYJpJbl9Y-ya8p2mOhaQwPbWzLyfppxnCT0 
[SE3000] [12] JWK type=oct id=subject-encrypt use=enc size=256 x5c=false pkcs#11=false thumbprint=JHqeGbu7dkFmAVaEkrxG0C8Xxd1ykTmk55iwPI90qJE 
[SE3000] [13] JWK type=oct id=refresh-token-encrypt use=enc size=256 x5c=false pkcs#11=false thumbprint=x0STKoEiQfddmz9QACOVd4S2w9tUx7inx2xgvjgzT6M 

The Java PKCS#11 provider and key store can be instructed to output additional logging.

10. Migration to dynamic key storage

Connect2id server deployments with a legacy or static JWK set can migrate to dynamic mode while retaining their existing keys. This enables online key rotation and revocation through the key store API, with a record of key changes.

To migrate the OpenID provider JWK set:

  1. Set keyStore.importIfEmpty.op to the complete existing JWK set.

  2. Remove the static configuration for this context: keyStore.staticJWKSet.op, jose.jwkSet and the legacy WEB-INF/jwkSet.json file, wherever present. Check external configuration sources for overrides.

  3. Configure keyStore.encJWK with an encryption key generated for your deployment. Dynamic mode stores the server keys in the database and uses this key to encrypt their private and secret material.

  4. Configure keyStore.apiAccessTokenSHA256 with the SHA-256 hash of an access token for the key store API. This enables the API, which is required for online key rotation and revocation.

  5. Set keyStore.importExp to a future Unix timestamp, no more than 24 hours ahead of the time the server starts. This limits the import window and prevents an accidental reimport after that window if the imported JWK set is later revoked.

  6. Restart the server with the new configuration. The JWK set is imported only if the OpenID provider context in the database is empty. Verify that the server uses dynamic mode and that the expected keys have been imported.

Example configuration (replace the placeholders with your own values):

# Encryption JWK for the database key store, optionally BASE64URL-encoded
keyStore.encJWK=[key-store-encryption-jwk]

# SHA-256 hash of the access token to enable the key store API
keyStore.apiAccessTokenSHA256=[access-token-sha256-hex]

# Complete existing OpenID provider JWK set, optionally BASE64URL-encoded
keyStore.importIfEmpty.op=[existing-op-jwk-set]

# Import expiry: Unix timestamp in seconds, within 24 hours of server startup
keyStore.importExp=[import-expiry-timestamp]

11. Key description

OpenID provider context

  • JWT signing keys — Public / private key pairs for signing ID tokens, JWT access tokens, UserInfo responses, authorisation responses and token introspection responses:

    • RSA with a key size of 2048, 3072 or 4096 bits.
    • EC with curve P-256, P-384, P-521 or secp256k1.
    • OKP with curve Ed25519.

    Each JWK must have a unique key ID (kid) and key use (use) of sig. RSA and EC signing keys can also be stored in a PKCS#11-compliant HSM.

    The public keys are published so that clients and resource servers can verify signatures.

    Supports rotation: Yes.

  • JWT encryption keys — Public / private key pairs that enable clients to encrypt JWT-secured authorisation requests (JAR) for the Connect2id server:

    • RSA with a key size of 2048, 3072 or 4096 bits.
    • EC with curve P-256, P-384 or P-521.

    Each JWK must have a unique kid and a use of enc.

    The public keys are published for clients to encrypt requests. The Connect2id server uses the corresponding private keys to decrypt them.

    Supports rotation: Yes.

  • Access token encryption key — Optional AES key for encrypting signed JWT access tokens to keep their contents confidential.

    Supported key sizes are 128, 192 and 256 bits. The JWK must have a unique kid and a use of enc.

    This key must be shared securely and out of band with every resource server that needs to decrypt the access tokens. It can be omitted if JWT access token encryption is not required.

    Supports rotation: Yes.

  • Secret HMAC key — Secret 256-bit key for applying HMAC-SHA-256 protection to session identifiers, authorisation codes, identifier-based access tokens and PAR URIs.

    The JWK must have a kid of hmac and a use of sig.

    This is a permanent key. Changing it invalidates the identifiers and tokens protected with the previous key.

    Supports rotation: No.

  • Refresh token encryption key — Secret 256-bit key for encrypting refresh token metadata and authenticating the entire refresh token.

    The JWK must have a kid of refresh-token-encrypt and a use of enc.

    This is a permanent key. Changing it invalidates refresh tokens protected with the previous key.

    Supports rotation: No.

  • End-user ID encryption key — Secret 256-bit key for encrypting pairwise subject identifiers with AES in SIV mode.

    The JWK must have a kid of subject-encrypt and a use of enc.

    This is a permanent key. Changing it changes the pairwise subject identifiers derived with the key, affecting how clients identify existing end-users.

    Supports rotation: No.

OpenID Federation context

  • Entity statement signing keys — Public / private key pairs for signing federation entity statements. Required when OpenID Federation is enabled.

    Supported key types:

    • RSA with a key size of 2048, 3072 or 4096 bits.
    • EC with curve P-256.
    • OKP with curve Ed25519.

    Each JWK must have a unique kid, a use of sig and an alg identifying the signing algorithm.

    RSA and EC signing keys can also be stored in a PKCS#11-compliant HSM.

    The public keys are included in issued Entity Configurations, allowing federation participants to verify entity statement signatures.

    Supports rotation: Yes.

12. Sample JWK sets

Sample OpenID provider JWK set

{ "keys" : [ { "kty" : "RSA",
               "use" : "sig",
               "kid" : "CXup",
               "n"   : "hrwD-lc-IwzwidCANmy4qsiZk11yp9kHykOuP0yOnwi36VomYTQVEzZXgh2sDJpGgAutdQudgwLoV8tVSsTG9SQHgJjH9Pd_9V4Ab6PANyZNG6DSeiq1QfiFlEP6Obt0JbRB3W7X2vkxOVaNoWrYskZodxU2V0ogeVL_LkcCGAyNu2jdx3j0DjJatNVk7ystNxb9RfHhJGgpiIkO5S3QiSIVhbBKaJHcZHPF1vq9g0JMGuUCI-OTSVg6XBkTLEGw1C_R73WD_oVEBfdXbXnLukoLHBS11p3OxU7f4rfxA_f_72_UwmWGJnsqS3iahbms3FkvqoL9x_Vj3GhuJSf97Q",
               "e"   : "AQAB",
               "d"   : "bmpuqB4PIhJcndRs_i0jOXKjyQzwBXXq2GuWxPEsgFBYx7fFdCuGifQiytMeSEW2OQFY6W7XaqJbXneYMmoI0qTwMQcD91FNX_vlR5he0dNlpZqqYsvVN3c_oT4ENoPUr4GF6L4Jz74gBOlVsE8rvw3MVqrfmbF543ONBJPUt3d1TjKwaZQlgPji-ycGg_P7K-dKxpyfQsC8xMmVmiAF4QQtnUa9vMgiChiO8-6VzGm2yWWyIUVRLxSohrbSNFhqF2zeWXePAw0_nzeZh3IDIMS5ABo92Pry4N3X-X7v_7nf8MGngK4duQ_1UkkLk-3u0I3tk_glsarDN0tYhzPwAQ" },
             { "kty" : "EC",
               "crv" : "P-256",
               "use" : "sig",
               "kid" : "yGvt",
               "d"   : "XnnhYQD6olmXKNQ2mBQ-ZOHEMUpYENnvGDNU3z9VVZ0",
               "x"   : "pvgdqM3RCshljmuCF1D2Ez1w5ei5k7-bpimWLPNeEHI",
               "y"   : "JSmUhbUTqiFclVLEdw6dz038F7Whw4URobjXbAReDuM" },
             { "kty" : "EC",
               "crv" : "P-384",
               "use" : "sig",
               "kid" : "9nHY",
               "d"   : "3zS7ECyMqZlENI9Xk6TqptEbZtoso3LmO4Hc9zs-VytU3Sgd8yHw2uUePAkGv_Fu",
               "x"   : "JPKhjhE0Bj579Mgj3Cn3ERGA8fKVYoGOaV9BPKhtnEobphf8w4GSeigMesL-038W",
               "y"   : "UbJa1QRX7fo9LxSlh7FOH5ABT5lEtiQeQUcX9BW0bpJFlEVGqwec80tYLdOIl59M" },
             { "kty" : "EC",
               "crv" : "P-521",
               "use" : "sig",
               "kid" : "tVzS",
               "x"   : "AZgkRHlIyNQJlPIwTWdHqouw41k9dS3GJO04BDEnJnd_Dd1owlCn9SMXA-JuXINn4slwbG4wcECbctXb2cvdGtmn",
               "y"   : "AdBC6N9lpupzfzcIY3JLIuc8y8MnzV-ItmzHQcC5lYWMTbuM9NU_FlvINeVo8g6i4YZms2xFB-B0VVdaoF9kUswC",
               "d"   : "AAnqLI9s0-hKAXtp0mXQHKoPBMDsnhgeh6HQP-1ScEVMl9-7WcJm2m_msXPyfT0O9Xbh4UDn9wdAi9bqt_4qEEjy" },
             { "kty" : "EC",
               "crv" : "secp256k1",
               "use" : "sig",
               "kid" : "iRTU",
               "x"   : "tcjSy7nIVZ2DVz-RKjqHIJqr5WDqZLS6fq4rEN6pfGY",
               "y"   : "2oqx5jvggJKy-LXFjpDOpL0g_SbiLylu_8xx-dBMQeQ",
               "d"   : "rtnqI1fWogLX3QaG_PykfGJyOZPNEwHo7glIJl3mrqE" },
             { "kty" : "OKP",
               "crv" : "Ed25519",
               "use" : "sig",
               "kid" : "27zV",
               "x"   : "0I6olrZGYml7JGusuKJW9G7D0DZ9UormSady9kR7V4Q",
               "d"   : "tYXIC35n-nNoVwZ5Rck02ndqFLyYcC8fNwhVFJjWB3c" },
             { "kty" : "RSA",
               "use" : "enc",
               "kid" : "IHMc",
               "n"   : "lLrhwERiPmq7XOz6Rwk8q4ey_OGcL4P56Ip01mzKMUfysIwo-nUdwDI_9ntYohpvqiTjnrtZOENhhoqne5M4hqpSfBMmCWSvWL_3wa8FanRWd6lPgGdKJ1a3vV0gLxnCbmdho1CSuSszV4736WkjdDhLcXSRN1kWwWbok94FdPD_egCyBY3cwhvuRzmUgE8LDh-VnNRh1BYc7e9yEMublza8qJpW-N5ljHEU0on08X-lsyl4djEac74H7taDcmtchPLYZy0-ZIxgLmosQ2aYIt6xycfPYsm5x9CGetUqhClpLLaTcyTGq_pH4ECdZtkYHcYJM-3q-XDZTqB6wUaggw",
               "e"   : "AQAB",
               "d"   : "N_IEMRqICgqD5_SMQGRNGgi1X0JOSeFPBBXw1See9uKle5t9XpjnVACS5tiHApMHJe0yYeb_LJbL_JvzXByIyr8Ov_VD_YyOGMg9HfIEC4Mvc1uQuDAiSKHqA6UgEheSd40TwSbxyg1iBrGUt4wA9hqm5kp-xV8RnDZljhmZ296nVPNNW3aXrqq2FPFn00s2Rh6gJbSTWhg6qQxTSVOO1n601TbWQGlP6mlXdIqXyzlwqwwOCcQIW88ws2jLmY3Hr4Le8nxL20xBACMYjR-9bO0senxbYUcew6GGscyiPe7I5X3P9cpZcRNeERIzsmtin1swvsyCK2cUUCtGpLpN4Q" },
             {
               "kty" : "EC",
               "crv" : "P-256",
               "use" : "enc",
               "kid" : "1yFA",
               "x"   : "_-aKZeuwWDv4v89dPGdKtpOuOepc_0qDZDhcv3omzX0",
               "y"   : "Gc5b7muOqbi4QvYJO24a4IqQoOY1pPM69DcpI605Vmw",
               "d"   : "lFj2hl_0MDs7D3yyTgU6LedcJ7NUZAs6noGzhZszsRA" },
             {
               "kty" : "EC",
               "crv" : "P-384",
               "use" : "enc",
               "kid" : "TqZ6",
               "x"   : "3Ex0yUSLvhaOriP8U78kZEEJXxkC0oQmwo1zHTe_nhgKx2YPS97-qmDdRMkByxJ9",
               "y"   : "MCosrhjIYP4lkoan45MxAZE3QB6IKau5nZHpQ_qDXH8jgcIo2l3M8wdN6iI08kcW",
               "d"   : "W4OifZsTcoIBwBteTM_8fwNKu7xFVlJEzVS-9YfJJK_QenjbedvcqTfzyiwh1b9F" },
             {
               "kty" : "EC",
               "crv" : "P-521",
               "use" : "enc",
               "kid" : "h38C",
               "x"   : "AVMBSexPHgq536pZQjN6Si1HAdUdfiW4xrdYzNHR2A9z4zovnKi5xrQ9hWX8QUs4ejVQ3bE9ufhOYL3D7oTwx9Jb",
               "y"   : "AeMeo858k_6ktxNhlpxBSwGL2hmTI1nBeGi2ZrMVl2qzdjOFf-AVFRSsE9DhAD9sWVUrGrzwONbfmqwIlgbjeH7L",
               "d"   : "AJGiS9ovRl2PrJz8ZSKokMaGXk-nJObJPtPiISPSxFJe1PHJWpEXollGAAYTI8DSiyO4gi7BHGq6T5JGB_zS2TqU" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "5C93",
               "k"   : "MaLXergNZ0bec14LDJkXTQ" },
             { "kty" : "oct",
               "use" : "sig",
               "kid" : "hmac",
               "k"   : "m5JZeVoU9lBV6y-d2jNelbjrxwosYjrSGg4STHLLm4g" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "subject-encrypt",
               "k"   : "QA4js08rUQsZfEoEoxu6LGgJgbHdmPG08XCKYSJTNJ0" },
             { "kty" : "oct",
               "use" : "enc",
               "kid" : "refresh-token-encrypt",
               "k"   : "pNzHVtVWJ8oluOGvesrmLgyVEVCkT6Os5f8e2PFEK9Y" } ] }

Sample OpenID Federation JWK set

{ "keys" : [ { "kty" : "RSA",
               "alg" : "RS256",
               "use" : "sig",
               "kid" : "exR5",
               "n"   : "l9TeUfN0jztln5hVq6Z3vwS47MCyonpO-kJSVMqccKgoUkxLzo_IH1ekKf-3X1Tu4KrKoDn7Nk6Wrusw9gOI9JCszV8rCE1_SCYnKI4mCwI9RXhCgXC0NkvXg-1ySHn9PjNEurGsgpIFqA2u-66KItFP_BLsUKGDfC1w73EymUJ6ZHGc1FnAXCusWgLARceOep4oAO8q3_oFNW4A__1IphYnJ6zdqYwBHK6PWf210SKP8LAJ0tlq7RTZyiB0DG9ina95UHNFIoJnc_g-AOCa1-ShDcUNpWtpL1j3vZnAHyG3pB_9xi4Ngo2-vlZQXnalZmDbk1Cog4N3hI-3DXTTMw",
               "e"   : "AQAB",
               "d"   : "YydZ9Oznzu48RIhoUkvJYc7EsaB6SE9VqmuLduJGXfADPROkYgZV69oBVIgyCajew4vl_dM_skyKbTsc41yVoRmmMAyZfreVitmXsw153LCesPKDhCLFHbxTx01W1-wKrQcwODf17-NKnGArSSPIBErrUDRPbay8wGiwmz4yjBDydZKYlFGwnt4R3MBzUB0nEhR_aKelUamdXyfOAT1gZh2cTJEMt7jzUbOKokJlaH3Yb3JOjI1n1RROxrwLW2tGoU7fPXSEULK5N9fddthXpDy1vwezYrdihIWdhSJd5xyvU85SuTYt0XHi3sDl1rc2iuJYpXOrQ3R92C-sLX00YQ" } ] }

13. Extracting keys from a JWK set

The jq tool can select keys from a JWK set by their ID, type, curve or use. The following commands read from jwkSet.json and output the matching JWK objects, including any private or secret key material.

To extract a JWK by its kid (key ID), for example subject-encrypt:

jq '.keys[] | select(.kid == "subject-encrypt")' jwkSet.json

To extract Ed25519 signing keys:

jq '.keys[] | select(.kty == "OKP" and .crv == "Ed25519" and .use == "sig")' jwkSet.json

To extract the shared AES keys for encrypting JWT access tokens, excluding the permanent subject and refresh token encryption keys:

jq '.keys[] | select(.kty == "oct" and .use == "enc" and .kid != "subject-encrypt" and .kid != "refresh-token-encrypt")' jwkSet.json

To output the selected keys as a JWK set, wrap the results in a keys array. For example:

jq '{keys: [.keys[] | select(.kty == "OKP" and .crv == "Ed25519" and .use == "sig")]}' jwkSet.json

To save the result to a separate file:

jq '{keys: [.keys[] | select(.kty == "OKP" and .crv == "Ed25519" and .use == "sig")]}' jwkSet.json > ed25519-signing-jwk-set.json