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 |
|---|---|---|
|
|
|
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 theP-256curve.eddsa:Ed25519– Generate an EdDSA key with theEd25519curve.
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:
-
jwks-gen.jar (PGP signature, validated with the Connect2id software delivery public key)
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 (forES384) and / or P-521 (forES512). -
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:
-
Set keyStore.importIfEmpty.op to the complete existing JWK set.
-
Remove the static configuration for this context: keyStore.staticJWKSet.op, jose.jwkSet and the legacy
WEB-INF/jwkSet.jsonfile, wherever present. Check external configuration sources for overrides. -
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.
-
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.
-
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.
-
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) ofsig. 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
kidand auseofenc.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
kidand auseofenc.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
kidofhmacand auseofsig.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
kidofrefresh-token-encryptand auseofenc.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
kidofsubject-encryptand auseofenc.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, auseofsigand analgidentifying 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