JsonWebKeys Extension
Introduction
The JsonWebKeys Extension exposes an endpoint to retrieve the public keys used to verify the Json Web Tokens created by FNZ Studio Solutions.
This endpoint is available at <host>/.well-known/jwks.json, and can also be accessed in FNZ Studio from System Configuration > Extensions > [JsonWebKeys Extension] > Open JWKS endpoint. The exposed keys are automatically rotated as described in the Key Rotation section below.
The endpoint has a cache mechanism which caches the response based on the extension configuration properties (System Configuration > Extensions > [JsonWebKeys Extension] > Edit Configuration). Every time the extension configuration is updated, the cache gets refreshed.
Keys stored in the key store with the privatekeyjwt_ alias prefix and those managed by the Key Rotation process are automatically exposed. For all other keys that need to be exposed, their alias must be added to the following configuration properties:
-
com.nm.extensions.jsonwebkeys.aliases- alias of the keys that are exposed in the JWKS endpoint and can be used for signing JWTs; -
com.nm.extensions.jsonwebkeys.encryption.aliases- alias of the key that are exposed in the JWKS endpoint and can be used for encryption.
The exposed keys are automatically rotated as described in the Key Rotation section. The endpoint has a cache mechanism which caches the response based on the extension configuration properties. Every time the configuration of the extension is updated the cache gets refreshed.
Properties
Key Rotation
Key rotation is the process for replacing old cryptographic keys used for signing and validating JWTs with new ones. Rotating keys on a regular basis is an industry standard.
The keys that are automatically generated by this extension have the following alias:
Base32.encode(appway-jwk-{timestamp}).toLowerCase(), where the timestamp represents the date when the key becomes active (used for signing).
The keys have a default lifetime of 8 months (configurable). During this lifetime, they can be used for signing. However, the keys are removed only after 12 months (lifetime x 1.5) so that already generated JWTs can still be validated.
The JWKS endpoint exposes the following keys:
- currently used — This key can be used for signing new JWTs and it is exposed in the JWKS endpoint.
- next in queue — This key is exposed in the JWKS endpoint so that the clients can cache it, but it cannot be used for signing new tokens.
- previously used — This key is exposed in the JWKS endpoint so that clients can still verify old JWT tokens, but it cannot be used for signing new tokens.
Key Rotation Process
The Key Rotation process involves three jobs:
KeyPairGeneratorKeyPairCleanup
KeyPairGenerator Job
The KeyPairGenerator job runs every week and checks the timestamp of the newest existing key. If this key has reached half of its lifetime, a new key is generated.
The timestamp of the new key that is generated is set in the future so that the clients have enough time to cache the new keys before they are used for signing.
The extension configuration property com.nm.extensions.jsonwebkeys.keypair.idle.time can be used to configure the time window to be added to the alias timestamp, which makes the key available but not able to sign a JWT. The configuration property is expressed in seconds and has a default value of 604800 seconds (7 days).
The new key pair is automatically added to the extension configuration property com.nm.extensions.jsonwebkeys.aliases and it is automatically exposed in the JWKS endpoint.
The KeyPairGenerator job has the following configurable properties:
com.nm.extensions.jsonwebkeys.keypairgenerator.job.cron.expression— Cron expression to schedule the job. Default: At 23:00 every Thursday;com.nm.extensions.jsonwebkeys.keypair.lifetime— Lifetime of a keypair (in seconds). Default: 21038400 seconds (8 months);com.nm.extensions.jsonwebkeys.keypairgenerator.job.enabled— Flag to enable/disable the KeyPairGenerator job. Default: true
KeyPairCleanup Job
The KeyPairCleanup job runs every week and cleans the old key pairs that reached their existence time (lifetime x 1.5). The KeyPairCleanup job has the following configurable properties:
com.nm.extensions.jsonwebkeys.keypaircleanup.job.cron.expression— Cron expression to schedule the job. Default: At 23:30 every Thursday;com.nm.extensions.jsonwebkeys.keypaircleanup.job.enabled: Flag to enable/disable KeyPair CleanUp job. Default: true
Signing JWTs
The Auth:GetJwksKeyIdForSignature Script Function returns the valid alias of the key that can be used for signing.
Therefore, JWTs must be signed only through the alias returned by this Script Function.
Example:
String $alias := Auth:GetJwksKeyIdForSignature();
String $algorithm := 'RS512';
PRINTLN('Creating JWT with key id ' & $alias & ' and algorithm ' & $algorithm);
//
Named String $claims := {}:String;
$claims['iss'] := 'http://localhost:8080/appway';
$claims['aud'] := 'appway';
$claims['exp'] := TOSTRING(Time:EpochSecond() + 86400);
$claims['sub'] := 'nm';
$claims['roles'] := 'Administrator,User';
//
Named String $headerClaims := {}:String;
$headerClaims['kid'] := $alias;
//
String $token := Auth:CreateJwtRsaSigned($algorithm, $alias, $claims, $headerClaims);
PRINTLN($token);
The extension provides an additional Script Function Auth:GetJwksKeyIds which returns all the aliases configured in the extension configuration property com.nm.extensions.jsonwebkeys.aliases. These aliases may contain manually configured keys or keys generated by the KeyPairGenerator job.
To manually create a key pair, use the Auth:GenerateKeyPair('test-jwks', 'password') Script Function.