The architecture of the API Server uses plugins to separate functionality into configurable and customizable components. Many of these plugins use JSON Web Tokens (JWTs) to transmit and/or receive the following:
Session information — returned from Nok Nok FIDO and non-FIDO authentication
Transaction information — returned after transaction confirmation
Credentials for an externally authenticated user — sent by an RP server after verifying a user with an External Authentication Method
A JSON object, called jwt_config, controls and configures JWT validation and generation. jwt_config specifies what algorithm and key to use, where to find the key, how long the JWT is valid, and which servers can issue a JWT to the API Server. JWT configuration is tenant-specific and that tenant is assigned in jwt_config.
You need to understand and modify this configuration object, if you do any of the following:
Generate or validate a JSON Web Token (JWT) that uses a different key or an algorithm other than HS256
Add or remove a server as an issuer of a JWT
Change the JWT's lifetime
Update the audience, this is usually the tenant
Enable the API Server to accept JWTs created by your backend server(s)
Add more keys to a JSON Web Key Set (JWKS) object
Add a Java KeyStore as a source of JSON Web Keys (JWKs)
Add a URL as a source of JWKs
Change how long a user session can be valid
For each of these plugins, the table below lists the name of the JWT configuration object, the purpose of the JWT, if the plugin generates a JWT, and if the plugin validates an issued JWT.
API Server Component | Configuration Object | Purpose of the JWT | Generates JWT? | Validates JWT? |
|---|---|---|---|---|
JWT Processor plugin | jwt_config | Session token | yes | yes |
Transaction plugin | jwt_config | Transaction token | yes | no |
External Authentication plugin | jwt_config | Credentials for the authenticated user when using an External Authentication Method | no | yes |
Table JWT Information Summary for API Server plugins
Using a JWT as a session token is a key concept in the S3 Suite. To understand how the session token is used, see Understanding the Session Token. To understand how the S3 Suite uses JWTs for external authentication, see Configuring an External Authentication Method.
You can optionally create a Default JWT Config, a tenant-wide jwt_config that controls JWT generation and validation for all of that tenant's API Server plugins. If you create a locally-defined JWT configuration object for an API Server plugin, like the JWT Processor plugin, then the settings in that locally-defined configuration override those in the Default JWT Config.
JSON Web Token Format describes the token format and claim set used by Nok Nok JWTs. The claims in a transaction confirmation JWT are slightly different from the claims in a standard JWT used by most plugins. To understand how a transaction confirmation token is used, see Transactions in the Developer Guide for Android, iOS or Web.
Overview of the JWT Configuration Object and JWT Configuration Object Fields start off by describing the structure and fields found in jwt_config. This provides the context to understand how to update this object to accomplish various tasks. Supported Algorithms list all the supported cryptographic and content encryption algorithms that you can use.
When you first install the S3 Suite, it automatically installs the default tenant. Only the JWT Processor plugin is installed with a predefined JWT configuration object. You can easily generate JWT configuration objects with default settings for the Default JWT Config or the remaining API Server plugins, see Generating JWT Configuration Objects.
Most organizations need to modify the JWT Processor plugin's jwt_config, often replacing the encryption algorithm, changing keys, or adding their own servers as issuers. When to Modify a JWT Configuration Object provides detailed instructions on how to perform common updates for any API Server plugin.
Finally, you want a frictionless approach to manage public keys for your RP backend servers that validate JWTs issued by the API Server. Instead of manually updating the JWKS (JSON Web Key Set) in the RP Server's configuration, have your RP server use key rotation and access the JWKS stored at an endpoint. The API Server provides predefined URL endpoints where it stores its JWKS. See Rotating Keys for Your RP Servers.
Overview of the JWT Configuration Object
jwt_config contains two main objects: generate and validate. generate contains the information needed to generate a JWT while validate contains the information needed to verify a received JWT. Because each issuer could use a different algorithm, key source, as well as other settings, the information required to verify a JWT is segregated by issuer. Consequently, validate contains an array of issuer objects.
The following is an example jwt_config with default settings for the JWT Processor plugin. This configuration generates and validates a session token using the symmetric HS256 algorithm with one secret key. The generated session token has a lifespan of 1 hour.
{
"generate":{
"issuer":"https://myApiServer.com",
"audiences":[
"default"
],
"nbf_delta":0,
"encryption":"",
"token_lifetime":3600,
"kid":"hs256_key",
"algorithm":"HS256",
"jwks_object":{
"keys":[
{
"kty":"oct",
"use":"sig",
"kid":"hs256_key",
"k":"-MooF_CY4pElMmcNZu93BJQUeQg_E9HwBu1LONc_WXA"
}
]
},
"jwks_keystore":{
"file":"/usr/share/tomcat/cert/keystore.jks",
"storepass":"changeit",
"keypass":{
"alias":"hs256_key",
"pass":"MyPrivateKeyPassword"
}
}
},
"validate":{
"issuers":[
{
"issuer":"https://myApiServer.com",
"audiences":[
"default"
],
"encryption":"",
"token_lifetime":3600,
"max_clock_skew":180,
"algorithm":"HS256",
"jwks_object":{
"keys":[
{
"kty":"oct",
"use":"sig",
"kid":"hs256_key",
"k":"-MooF_CY4pElMmcNZu93BJQUeQg_E9HwBu1LONc_WXA"
}
]
},
"jwks_keystore":{
"file":"/usr/share/tomcat/cert/keystore.jks",
"storepass":"changeit",
"keypass":{
"alias":"hs256_key",
"pass":"MyPrivateKeyPassword"
}
},
"jwks_uri":"https://evaluation93.noknoktest.com:8443/gwtutorial/jwks.json"
}
]
}
}JWT Configuration Object Fields
This section starts by covering the 3 types of key sources that can be used in a JWT configuration object because key sources are specified in both the generate and validate objects. You can also use a certificate chain as an alternate way to provide a key and validate a JWT. Finally, the section describes the fields that are present in the generate and validate objects.
Key Sources
JWT generation and validation require that you specify a key source where the key required to sign or decrypt the JWT can be found. jwt_config enables you to specify up to 3 sources for your JWT keys.
Key Source | Corresponding Field | Note |
|---|---|---|
JSON Web Key Set (JWKS) | jwks_object | Embedded in the JWT configuration object and stored in the Server database. Easy to read because it's in text format. Tutorial Web App includes a sample JSON Web Key (JWK) Set file located at gwtutorial/jwks.json. |
Java KeyStore | jwks_keystore | Stored outside of the Server databases. Protected by a password. |
URL | jwks_uri | Only used to verify JWTs. Intended for storing public asymmetric keys at a single URL. |
List of URLs | jwks_uris | Only used to verify JWTs. Intended for storing public asymmetric keys at multiple URLs. |
In the generate object, only one of jwks_object or jwks_keystore is required, although you can use both.
In the validate object, only one of jwks_object, jwks_keystore, jwks_uri, or jwks_uris is required. You can use either jwks_uri or jwks_uris. You can choose to use all 3 types of key stores (JWKS, Java KeyStore, and URL(s)) or any combination.
All keys from all specified sources are fetched and cached by the Server. In the case of multiple key sources, which key to use for validation is based on the algorithm and kid from the JWT header. Which key to use for generation is determined by the algorithm and kid found in the generate section of the jwt_config. Make sure that the kid for each keys is unique.
For instructions on how to automatically rotate asymmetric public keys, see Rotating Public Keys for JWT Validation.
Using a Certificate Chain
A certificate chain is an additional mechanism for providing a key and validating a JWT. The API Server can assign a certificate chain to a JWT's x5c header parameter when it generates a JWT. It can also validate JWTs that contain a certificate chain.
To generate a JWT that contains a certificate chain, the JWK that the API Server uses from its generate object must have a certificate chain assigned to its x5c parameter. That key is stored in a Java Keystore or JWKS.
To validate a JWT that contains a certificate chain, you specify your Public Key Infrastructure (PKI) in jwt_config for the appropriate issuer. The API Server checks the pki object in jwt_config's validate object to determine if it should validate the certificate chain. The pki object includes the trust store and options for checking for revoked certificates. The fields of the pki object are described in validate fields.
generate Fields
The values contained in these fields specify the values that are assigned to the claim set when the API Server creates a JWT.
Field Name | Description |
|---|---|
algorithm | Mandatory. String. The cryptographic algorithm for a JWT. For valid values, refer to Cryptographic Algorithms. |
audiences | Mandatory. An array containing one string: a Nok Nok tenant name. This jwt_config was created for this tenant. Used as the value for the aud claim. |
encryption | Mandatory for a JWE. String. The content encryption algorithm for a JWE. When encryption has a value, algorithm must contain one of the JWE algorithms listed in Encrypted JWT (JWE). For valid values, refer to Content Encryption Algorithms. |
issuer | Mandatory. String. Your API Server's URL. For example, "https://example.com:8443". When the API Server generates a JWT, it inserts this as the value for the JWT's iss claim. |
jti_claim | Optional. Boolean. Whether to include the jti claim in the JWT.
|
jwks_cache_refresh_interval | Optional. Integer. The amount of time, in seconds, to wait before updating the key cache (JWK set). For details, see Rotating Private Keys for JWT Generation. You can control cache refresh by using one of the values below.
|
jwks_keystore | Optional if you use jwks_object. An object containing information about a Java KeyStore. Contains the subfields listed in the rows below. If you use a file for your Java Keystore, you must provide the following fields:
You can optionally provide jwks_keystore.keypass.pass. |
jwks_keystore.file | Optional. String. The full path of the Java KeyStore file. |
jwks_keystore.keypass.alias | Optional. String. The key's alias name in the KeyStore. The alias's name must be the same as the key id, in other words, kid = jwks_keystore.keypass.alias. |
jwks_keystore.keypass.pass | Optional. String. The password for the key. If a key password is not specified, then the value of jwks_keystore.storepass is used. An empty password (i.e. password length is 0) assumes that the key is not protected in the KeyStore. |
jwks_keystore.keys | Optional. A stringified JSON array with key references used when jwks_keystore.provider (below) contains the value "NokNokCryptoProvider". |
jwks_keystore.provider | Optional. String. Name of the security provider to use. This must be set to "NokNokCryptoProvider" if you are creating a Crypto Plugin. Nok Nok assumes that you have configured this provider in your Java platform, see Oracle's How to Implement a Provider in the Java Cryptography Architecture, Step 8.1 Configure the Provider. |
jwks_keystore.storepass | Optional. String. The password for the KeyStore. |
jwks_keystore.type | Optional. String. Type of the KeyStore to use. Defaults to JKS. Can be a standard keystore type, e.g. PKCS12, or a custom one. |
jwks_object | Optional if you use jwks_keystore. JWK set object. |
kid | Optional. String. The key identifier. Must match one of the keys contained in jwks_object or one of the aliases in jwks_keystore. The API Server uses this to identify the key to use with the algorithm. If omitted, the first key in the set that matches the specified algorithm is used. The API Server inserts this into the header of the generated JWT. |
nbf_delta | Optional. Integer, 0 or greater. Additional time from the JWT issue time that is specified by the iat claim in seconds to generate an nbf claim. Default is 0. |
token_lifetime | Mandatory. Integer, 0 or greater. Token lifetime in seconds. Used to calculate the generated JWT's expiration time exp claim. The token expiration time is calculated as max(iat, nbf) + token_lifetime |
type | Optional. String. The media type. The API Server assigns type's value to the generated JWT's typ header parameter. The default is an empty string. If your backend servers don't use media type, use the default value. For more about typ and media types see typ in RFC 7519. |
validate Fields
The validate object has one top-level field, an array called issuers. Each item in the issuers array is an object that corresponds to an issuer. The API Server uses the issuer object to validate JWTs it receives from that issuer. The field descriptions for the issuer object are listed in the table below.
Your backend servers that generate and send JWTs to the API Server are candidates whose information could be added to issuers. If you have backend servers that use the same cryptographic algorithm and sources for keys, then they are logically the same issuer and need only one issuer object to represent them. The JWTs that they send to the API Server must match the information contained in their issuer object.
Field Name | Description |
|---|---|
absolute_timeout | Optional. Integer. Absolute timeout of the user session in seconds. Prevents JWTs from being renewed indefinitely. If the amount of time in absolute_timout has elapsed since the user last authenticated, this forces them to reauthenticate. The API Server first checks if the JWT has expired. If the JWT is valid and has values for the auth_time claim and absolute_timeout field, the API Server verifies that the time passed since auth_time is less than absolute_timeout. |
algorithm | Optional. String. The cryptographic algorithm for a JWT. If specified, the algorithm in the JWT header is checked against this field for matching. If it doesn't match, then the validation fails. For valid values, refer to Cryptographic Algorithms. |
audiences | Mandatory. An array containing one string: a Nok Nok tenant name. If the API Server is the issuer, then audiences must match generate.audiences. |
encryption | Mandatory for a JWE. String. The content encryption algorithm for a JWE. When encryption has a value, algorithm must contain one of the JWE algorithms listed in Encrypted JWT (JWE). For valid values, refer to Content Encryption Algorithms. |
issuer | Mandatory. String. The issuer's URL. Must match the JWT's iss claim. Two or more of your backend servers can share the issuer object, as long as they use the same field values, as described above, to generate their JWTs. The API Server ignores the backend server's web origin. |
jwks_cache_refresh_interval | Optional. Integer. The amount of time, in seconds, to wait before updating the key cache (JWK set). See Rotating Private Keys for JWT Generation for details. You can control cache refresh by using one of the values below.
|
jwks_keystore | Optional if you use one of jwks_object, jwks_uri or jwks_uris. An object containing information about a Java KeyStore. Contains the 6 fields listed in the rows below. If you use a file for your Java Keystore, you must provide the following fields:
You can optionally provide jwks_keystore.keypass.pass. |
jwks_keystore.file | Optional. String. The full path of the Java KeyStore file. |
jwks_keystore.keypass.alias | Optional. String. The key’s alias name in the KeyStore. The alias's name must be the same as the key id from the JWT's header in order to match the KeyStore's key. |
jwks_keystore.keypass.pass | Optional. Specifies the key password in the keyStore. If a key password is not specified, then the KeyStore password is used. An empty password, or password length of 0, assumes that the key is not protected in the KeyStore. |
jwks_keystore.provider | Optional. String. Name of the security provider to use. Nok Nok assumes that you have configured this provider in your Java platform, see Oracle's How to Implement a Provider in the Java Cryptography Architecture, Step 8.1 Configure the Provider. |
jwks_keystore.storepass | Optional. The password for KeyStore. |
jwks_keystore.type | Optional. String. Type of the KeyStore to use. Defaults to JKS. Can be a standard keystore type or a custom one. |
jwks_object | Optional if you use one of jwks_keystore, jwks_uri or jwks_uris. JWKS object. |
jwks_uri | Optional if you use one of jwks_object, jwks_keystore, or jwks_uris. String. URL where a JWK set is located. The URL should only contain public asymmetric keys. Can be used to implement key rotation. |
jwks_uris | Optional if you use one of jwks_object, jwks_keystore, or jwks_uri. An array of strings. Each element is a URL where a JWK set is located. The URL should only contain public asymmetric keys. Can be used to implement key rotation. |
max_clock_skew | Optional. Integer. The maximum clock skew in seconds. Accounts for clock skew when processing exp, nbf, or iat claims. Default: 60 seconds. |
pki | Optional. An object containing information about a Public Key Infrastructure (PKI). Specifies options for certificate chain validation. Used when the JWT header includes the x5c attribute containing a certificate chain. Contains the fields listed below. |
pki.enabled | Mandatory if you use pki. Boolean.
|
pki.truststore | Optional. An object containing information about a trust store. The trust store contains the trusted root certificates used to validate the certificate chain. Contains the 5 fields listed below. If not specified, the system default trust store is used. Specify the default trust store using Java system properties. |
pki.truststore.type | Optional. String. Type of the KeyStore to use as a trust store. Defaults to JKS. Can be a standard keystore type or a custom one. |
pki.truststore.provider | Optional. String. Name of the security provider to use. If not specified, the default provider is used. Nok Nok assumes that you have configured this provider in your Java platform, see Oracle's How to Implement a Provider in the Java Cryptography Architecture, Step 8.1 Configure the Provider. |
pki.truststore.file | Optional. String. The full path of the Java trust store file. |
pki.truststore.storepass | Optional. String. The password for the trust store. |
pki.truststore.update_check_interval | Optional. Integer. Amount of time, in seconds, to wait before reloading the trust store. Defaults to -1 which means the trust store is loaded once and never reloaded. |
pki.revocation | Optional. An object that specifies certificate revocation checking options. If not specified, revocation check is not performed. Contains the 2 fields below. |
pki.revocation.enabled | Optional. Boolean.
|
pki.revocation.options | Optional. Array of strings. Specifies options to use to check for revoked certificates. See Oracle’s PKIXRevocationChecker.Option for valid values and defaults. Strings are not case sensitive. |
token_lifetime | Optional. Integer. Must be 0 or greater. Defaults to 0. JWT lifetime in seconds. Verifies the age of the JWT if the iat or nbf claim is available. The API Server verifies that the JWT is still valid by comparing its age to its exp claim. If the JWT is valid and token_lifetime has a value, the API Server next compares the JWT's age to token_lifetime. Token age is calculated as |
type | Optional. String. The media type of the JWT. The API Server checks the typ parameter in the incoming JWT's header against type's value. |
Supported Algorithms
Cryptographic Algorithms
JWTs can use the cryptographic algorithms listed in the tables below. Assign the strings in the Value column to jwt_config's algorithm parameter.
Signed JWT (JWS)
JWT with HMAC protection (symmetric)
Value | Description |
|---|---|
HS256 | HMAC with SHA-256, requires 256+ bit secret |
HS384 | HMAC with SHA-384, requires 384+ bit secret |
HS512 | HMAC with SHA-512, requires 512+ bit secret |
JWT with RSA Signature (asymmetric)
Value | Description |
|---|---|
RS256 | RSA PKCS#1 signature with SHA-256 |
RS384 | RSA PKCS#1 signature with SHA-384 |
RS512 | RSA PKCS#1 signature with SHA-512 |
JWT with ECDSA Signature (asymmetric)
Value | Description |
|---|---|
ES256 | ECDSA with SHA-256 |
ES384 | ECDSA with SHA-384 |
ES512 | ECDSA with SHA-512 |
Encrypted JWT (JWE)
All encryption algorithms listed below work with any of the six standard available content encryption algorithms listed in Content Encryption Algorithms.
JWE with shared key
Value | Description |
|---|---|
dir | Direct use of a shared symmetric key as the Content Encryption Key (CEK) for the block encryption step (rather than using the symmetric key to wrap the CEK). |
JWT with AES encryption
AES and AES GCM key wrap encryptor of JWE objects
Value | Description |
|---|---|
A128KW | AES Key Wrap Algorithm (RFC 3394) using 128-bit keys |
A192KW | AES Key Wrap Algorithm (RFC 3394) using 192-bit keys |
A256KW | AES Key Wrap Algorithm (RFC 3394) using 256-bit keys |
A128GCMKW | AES in Galois/Counter Mode (GCM) (NIST.800-38D) 128-bit keys |
A192GCMKW | AES in Galois/Counter Mode (GCM) (NIST.800-38D) 192-bit keys |
A256GCMKW | AES in Galois/Counter Mode (GCM) (NIST.800-38D) 256-bit keys |
JWT with RSA encryption
Value | Description |
|---|---|
RSA1_5 | RSAES PKCS1 V1.5 |
RSA-OAEP | RSAES using Optimal Asymmetric Encryption Padding (OAEP) (RFC 3447) |
RSA-OAEP-256 | RSAES using Optimal Asymmetric Encryption Padding (OAEP) (RFC 3447), with the SHA-256 hash function and the MGF1 with SHA-256 mask generation function. |
JWT with ECDH encryption
Elliptic Curve Diffie-Hellman encryptor of JWE objects
Value | Description |
|---|---|
ECDH-ES | Elliptic Curve Diffie-Hellman Ephemeral Static (RFC 6090) key agreement using the Concat KDF, as defined in section 5.8.1 of NIST.800-56A, with the agreed-upon key being used directly as the Content Encryption Key (CEK) (rather than being used to wrap the CEK) |
ECDH-ES+A128KW | Elliptic Curve Diffie-Hellman Ephemeral Static key agreement per ECDH-ES, but where the agreed-upon key is used to wrap the Content Encryption Key (CEK) with the A128KW function (rather than being used directly as the CEK) |
ECDH-ES+A192KW | Elliptic Curve Diffie-Hellman Ephemeral Static key agreement per ECDH-ES, but where the agreed-upon key is used to wrap the Content Encryption Key (CEK) with the A192KW function (rather than being used directly as the CEK) |
ECDH-ES+A256KW | Elliptic Curve Diffie-Hellman Ephemeral Static key agreement per ECDH-ES, but where the agreed-upon key is used to wrap the Content Encryption Key (CEK) with the A256KW function (rather than being used directly as the CEK) |
Content Encryption Algorithms
A JWE can use the content encryption algorithms listed in the table below. Assign the strings in the Value column to jwt_config's encryption parameter.
Value | Description |
|---|---|
A128CBC-HS256 | AES 128 CBC HMAC SHA 256 authenticated encryption using a 256-bit key |
A192CBC-HS384 | AES 192 CBC HMAC SHA 384 authenticated encryption using a 384-bit key |
A256CBC-HS512 | AES 256 CBC HMAC SHA 512 authenticated encryption using a 512-bit key |
A128GCM | AES in GCM mode using a 128-bit key |
A192GCM | AES in GCM mode using a 192-bit key |
A256GCM | AES in GCM mode using a 256-bit key |
Generating JWT configuration objects
After you install the S3 Suite or create a new tenant, many of the API Server plugins do not have a JWT configuration object defined for them, and the default JWT configuration object is also not defined yet. Prepare your own JWT configuration objects with your preferred algorithm and options. Customize them using the instructions in When to Modify jwt_config. Finally, upload the JWT configuration objects to the API Server.
Use the instructions in this section to generate configuration objects with default settings for the Default JWT Config or any API Server plugin. You can either use the Admin Console or nnl-mgmt.sh to generate JWT configuration objects.
When you use the Admin Console to generate a JWT configuration object it contains both the generate and validate objects. This is true even if the API Server plugin only generates a JWT or only validates a JWT. The API Server plugin ignores the fields in the generate or validate object if it doesn't need it.
The Default JWT Config
The Default JWT Config object is defined in the API Server's Main object.
The default settings generate and validate a JWT using the symmetric HS256 algorithm with one secret key. The generated JWT has a lifespan of 1 hour. For a production deployment, replace this with a JWT that uses an asymmetric algorithm.
Using the Admin Console
Login and, if needed, switch to the desired tenant. Navigate to Configuration > API Server > Authentication API.
Expand the Main panel. Find the Default JWT Config label and click its Generate button. Confirm that you want to generate a new configuration object. To view the configuration, click the Default JWT Config label.
.png?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
Using nnl-mgmt.sh
Use the nnl-mgmt.sh's apiserver create command to generate a Default JWT Config. For details on apiserver create command, see API Server Configuration Commands. In the example below, replace https://myAPIServer.com with the URL for your API Server.
./nnl-mgmt.sh apiserver create -tenantid newtenant -type Main -name jwt_config -issuer "https://myAPIServer.com"Configuring an API Server component to use the default JWT Config
You can explicitly set any API Server Component to use the Default JWT Config instead of its locally-defined JWT configuration object.
Using the Admin Console
Login and, if needed, switch to the desired tenant.
Navigate to Configuration > API Server.
Find the panel containing the API Server plugin and expand it, click the Modify icon next to the plugin.

In the plugin configuration page click the Use Default button.
.png?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
If the Use Default button is inactive, then the plugin is already using the Default JWT Config. If this is the case, you see a screen similar to what is shown below when you click the name of the API Server plugin.
.png?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
Using nnl-mgmt.sh
Use the nnl-mgmt.sh's apiserver delete command to delete the API Server plugin's locally-defined JWT configuration object. This forces the plugin to use the Default JWT Config.
The example below deletes the JWT External Authentication plugin's JWT configuration object. For details on apiserver delete command, see reference to the API Server Configuration Commands.
./nnl-mgmt.sh apiserver delete -tenantid Marketing -type ExternalAuthenticationPlugin -name jwt_configJWT Processor plugin
The default settings for this plugin's configuration object generate and validate a session token using the symmetric HS256 algorithm with one secret key. The generated JWT has a lifespan of 1 hour. The API Server is configured as a server that generates and issues JWTs. So the API Server appears in the validate object as an issuer. For a production deployment, replace the symmetric algorithm with an asymmetric algorithm which is more secure.
Using the Admin Console
Login and, if needed, switch to the desired tenant. Navigate to Configuration > API Server > Authentication API.
Expand the Session Plugins panel. Find the JWT Processor label and click the Edit icon. In the plugin’s configuration page click the Generate button. Confirm that you want to generate a new configuration object. To activate the plugin, go back to plugin list and click the activate icon.
Using nnl-mgmt.sh
Use the nnl-mgmt.sh's apiserver create command to generate new JWT configuration objects. In the example below, replace https://example.com with the URL for your API Server.
./nnl-mgmt.sh apiserver create -tenantid newtenant -type SessionPlugin -name jwt_config -issuer "https://example.com"Transaction plugin
The default JWT configuration for this plugin generates a JWT using the symmetric HS256 algorithm with one secret key. The generated JWT has a lifespan of 1 hour. For a production deployment, replace this with a JWT that uses an asymmetric algorithm. This plugin does not validate a JWT.
Using the Admin Console
Login and, if needed, switch to the desired tenant. Navigate to Configuration > API Server > Authentication API.
Expand the Transaction Plugin panel. Find the JWT Transaction Processor label and click the Edit icon. In the plugin’s configuration page click the Generate button. Confirm that you want to generate a new configuration object. To activate the plugin, go back to plugin list and click the activate icon.
Using nnl-mgmt.sh
Use the nnl-mgmt.sh's apiserver create command to generate new JWT configuration objects. In the example below, replace https://example.com with the URL for your API Server.
./nnl-mgmt.sh apiserver create -tenantid newtenant -type TransactionPlugin ‑name jwt_config ‑issuer "https://myAPIServer.com"JWT External Authentication Plugin
The default JWT configuration for this plugin validates a JWT with a lifespan of 3 minutes that was encoded using the symmetric HS256 algorithm with one secret key. This plugin does not generate a JWT.
Using the Admin Console
When you generate a JWT configuration object for the JWT External Authentication plugin using the Admin Console, the API Server appears as an issuer in the validate object. After generation, edit the JWT configuration object and replace the API Server's URL with the URL of your RP server that is responsible for authenticating the user and issuing the JWT. Refer to Adding an Additional Issuer.
Login and, if needed, switch to the desired tenant. Navigate to Configuration > API Server > Authentication API.
Expand the External Authentications Plugins panel. Find the JWT Authentication Method label and click the Edit icon. In the plugin’s configuration page click the Generate button. Confirm that you want to generate a new configuration object. To activate the plugin, go back to plugin list and click the Activate icon.
Using nnl-mgmt.sh
Use the nnl-mgmt.sh's apiserver create command to generate a new JWT configuration object. In the example below, replace https://example.com with the URL for your RP server that will authenticate the user and issue a JWT.
./nnl-mgmt.sh apiserver create -tenantid newtenant -type ExternalAuthenticationPlugin -name jwt_config -issuer "https://example.com"When to modify a JWT configuration object
While the built-in support for a JWT signed with HS256 is easy and convenient, your circumstances can dictate that you use a different key, a different algorithm, a JWE instead of a JWS, and so on. This section identifies common scenarios that require updating a JWT configuration object and lists the fields that you need to change.
The instructions in the subsections below outline which jwt_config fields to modify. These instructions assume that you are familiar with the structure and fields in jwt_config. For detailed information about jwt_config, see JWT Configuration Object Fields.
Note: When you export a JWT Configuration Object, the private keys are obscured. When you import the modified JWT Configuration Object back into the API Server, the obscured keys are skipped and the corresponding keys from the existing JWT Configuration Object are preserved.
Adding an Additional Issuer
This task only applies to the JWT Processor and JWT External Authentication plugins.
The JWT Processor and the JWT External Authentication plugins can validate JWTs issued by your backend servers. Your backend servers that issue JWTs to the API Server are candidates for issuers to add to jwt_config. If you have backend servers that use the same cryptographic algorithm and sources for keys, then they are logically the same issuer and need only one issuer item in the issuers array.
Begin by exporting the JWT configuration object. Open this file in an editor. To create a new issuer object in the validate.issuers array, copy an existing issuer from that array. Update the following fields:
Field | Updated Value |
|---|---|
issuer | The URL of your backend server |
algorithm | The algorithm used by your backend servers to encrypt the JWT |
Specify the JWK source. At least one of the following. | |
jwks_object | Your JWKS object |
jwks_keystore | Your Java KeyStore |
jwks_uri | Your URL |
jwks_uris | Your array of URLs |
{
"issuer": "https://myApiServer.com",
"audiences": [
"default"
],
"encryption": "",
"token_lifetime": 3600,
"max_clock_skew": 180,
"algorithm": "HS256",
"jwks_object": {
"keys": [
{
"kty": "oct",
"use": "sig",
"kid": "hs256_key",
"k": "-MooF_CY4pElMmcNZu93BJQUeQg_E9HwBu1LONc_WXA"
}
]
}
}Insert your new issuer object into the validate.issuers array and save. Then import the updated JWT configuration object into your API Server plugin.
Updating the Algorithm and Key
The fields that you update depend on whether you use a symmetric or asymmetric algorithm.
If you are updating the algorithm and key in the JWT Processor plugin's JWT configuration object, follow the instructions below to update both the generate and validate objects.
For the Transaction plugin, only update the generate object.
If you are updating your backend server's algorithm and key, update your server's issuer object in the validate.issuers array. No changes are needed to the generate object. This applies to the JWT Processor or External Authentication plugins.
Symmetric Algorithm
Export the JWT configuration object.
In the generate object, modify the following properties. For a list of valid algorithms, see Supported Algorithms.
algorithm: Assign the algorithm you are using
kid: Assign your secret key's ID
jwks_object: If you use this as your key source, update an existing JSON Web Key (JWK) object with your key's JWK or insert your key's JWK in the keys array.
jwks_keystore: Technically, you aren't changing this field's value. If you've set up a Java KeyStore using this object, update or insert your key's JWK in this KeyStore.
In the validate object, in the issuer object corresponding to the API Server, modify the following properties:
algorithm: Assign the algorithm you are using
jwks_object: If you use this as your key source, update or insert your key's JWK in the keys array.
jwks_keystore: Technically, you aren't changing this field's value. If you've set up a Java KeyStore using this object, update or insert your public key's JWK in this KeyStore.
Import the updated configuration object.
Asymmetric Algorithm
Asymmetric algorithms generate 2 keys: private and public. The private key's information goes into the generate object while the public key's information goes into the validate object.
Export the JWT configuration object. In the generate object, modify the following properties. For a list of valid algorithms, see Supported Algorithms.
algorithm: Assign the algorithm you are using
kid: Assign your private key's ID
jwks_object: If you use this as your key source, update an existing JSON Web Key (JWK) object with your private key's JWK or insert your private key's JWK in the keys array
jwks_keystore: Technically, you aren't changing this field's value. If you've set up a Java KeyStore using this object, update or insert your private key's JWK in this KeyStore.
In the validate object, for the issuer affected by this change, modify the following properties:
algorithm: Assign the algorithm you are using
jwks_object: If you use this as your key source, update an existing JWK object with your public key's JWK or insert your public key's JWK in the keys array
jwks_keystore: Technically, you aren't changing this field's value. If you've set up a Java KeyStore using this object, then update or insert your public key's JWK in this KeyStore.
jwks_uri: Assign a server URL, if this field is blank and you choose to use this as your key source. In the JWK set stored at the server, update or insert the public key in the JWK set.
jwks_uris: Update an existing server URL in the array or add a new one if you choose to use this as your key source. In the JWK set stored at the servers, update or insert the public key in the JWK set.
Import the updated configuration object.
The example below shows a jwt_config for the JWT Processor plugin that was modified to use an RSA 256 algorithm with a private key of "EPoe1856". This configuration object uses a jwks_object as the key source. The updated fields and their values are highlighted.
{
"generate":{
"issuer":"https://example.com:8443",
"audiences":[
"default"
],
"nbf_delta":0,
"encryption":"",
"token_lifetime":3600,
"kid":"EPoe1856",
"algorithm":"RS256",
"jwks_object":{
"keys":[
{
"p":"63LVPDjFtKRRMNrjq1-PPj4d1z5Re8lRySH67OMIrlpYtmoutpIgKb2av2DBBkGzK_48gxIlpZdusw9AOHqksdQ7vIshBz1OA1odBs3dVPeBUvdZNQ3EBJ_wGLEOCHbrWnPxFxWkeUH8x0xhXxeQUepBI-dLh0cx1IZhu48ZoHE",
"kty":"RSA",
"q":"qujNF7q3HsfRS2bRxdfjcBdCh1acUMIhrM7DZthgLTuHhtq2oentMeKic3dWUdaKvpi2jU2_E63A96no5lZJ3JIUH1ldpG5eLwpbkT1uv0sapEVjCW0WJWwt5w0cCPOGsAOJeMnbKWrGZZFKb_88qzaV2zvdnJLyGx-8poj-Jcc",
"d":"h11990yS4m_vm6sdr7LfjDm1nOFxBiEtJLzWuBwlaRuoMMOP-e2kmpY5q_JFv_M78_TdO5GbUbuLQV3K9AkpzZRVqavXd9HfBQlCN_kBg3bQH9fl_KabSd6tRtQHuhIcfGTmYdDpY7FjlcRzlXuKqvcHEkl7UlIZM1sSUIwD6PbAK66g4DIM_lMCJEvE2c6GPME-P5y5KVc7SuU_yjjeOdV2vGxhMoTn9FVp34_qB0_T787_E0JY6c6GZt6baXvFeoSAF6E060ovzMNmGt3fckvzw_Pco6De6Y3NsOVQ5_FZxgYimKOWcsXvxzHlYAV4GiRcycUNOEzOhN20TL0NwQ",
"e":"AQAB",
"use":"sig",
"kid":"EPoe1856",
"qi":"6CF-N3u2ex-1ZfrlzNTrIPwQVrHoExOEj84T295vEYTudW-xYMzZU95GCLL0C0x8j7zqqAN5WVkVcKPP8w6bBRGcMC3ZkjOIJ9zS_SYxlK1cJe22dOu3U5AOrONsryGYQhrRRDEmLF54EBXv3_UeJ71fLJgRNLzaohnIgglqIt8",
"dp":"KgemvwhXaqbGg5UffTEizfaitxC91P4cJm51b6Ibo5wnJ_EOg7LUIP9ix3ULIAXMaTcKME-l_shoj3hSe4KRMdl0DHU9oSA1c-27LsLDFu7T3C6hcxIRAs5WOuIoYiRwYQY_bGKFqMu5xw4Ad8wqDCVoGXOpjO2NnKWcfrHN3lE",
"alg":"RS256",
"dq":"SMTWjkPxtClf87rTlmlVbWR57yXxaHE_5VQj3qZCTQALtF9rY4U2eQcGJCOrnSy75msfTwrLUJWqk8jEYU5cJI4OA0sJk_lqIJ1IX47ImKphrY_dmyXXSBfHc5khVq5ZqpfW8JcBuaC82IIEL6t9KWkUZUQYF5J5gxMAP-gUTgE",
"n":"nTBeTAQS-VOpSfm_HMUAg1SfOT-cmzZKwtr0-2CTyXbt8JOfEH2xkLykbdL-L8bv8rjx971DFW6HB8Lf_ll1ETNxfVEnQKlZWB3cf4d-32f4oKU1J56j293QLgTD6H50rQ_X0uQsQWcimwCvv-mAmwdB979Ahwz_dAWT5cGo81OhM2m0IpopJP4sM_uJdr-18QnyLSjqPxXlXwPP16Tzup2gf0BcwKCNOkbvBukKDf_AlciOmijfZB5sEepmBZvTKn3iK8Bc2y2aeDndm9JRR1CYwMHMeuU1C14SBqBNHVgz7CbuUvnELdSBTaBBASsHV2sizLIYDkIx07JqKToM1w"
}
]
}
},
"validate":{
"issuers":[
{
"issuer":"https://example.com:8443",
"audiences":[
"default"
],
"encryption":"",
"token_lifetime":3600,
"max_clock_skew":180,
"algorithm":"RS256",
"jwks_object":{
"keys":[
{
"kty":"RSA",
"e":"AQAB",
"use":"sig",
"kid":"EPoe1856",
"alg":"RS256",
"n":"nTBeTAQS-VOpSfm_HMUAg1SfOT-cmzZKwtr0-2CTyXbt8JOfEH2xkLykbdL-L8bv8rjx971DFW6HB8Lf_ll1ETNxfVEnQKlZWB3cf4d-32f4oKU1J56j293QLgTD6H50rQ_X0uQsQWcimwCvv-mAmwdB979Ahwz_dAWT5cGo81OhM2m0IpopJP4sM_uJdr-18QnyLSjqPxXlXwPP16Tzup2gf0BcwKCNOkbvBukKDf_AlciOmijfZB5sEepmBZvTKn3iK8Bc2y2aeDndm9JRR1CYwMHMeuU1C14SBqBNHVgz7CbuUvnELdSBTaBBASsHV2sizLIYDkIx07JqKToM1w"
}
]
}
}
]
}
}Managing Keys for a JWT
The API Server caches the keys for the JWT to speed up processing. The cache is formed from keys specified by the jwks_object, the jwks_keystore, and either the jwks_uri or the jwks_uris in the jwt_config. Export the JWT configuration object then make the updates described in the sections below. When you are finished, import the JWT configuration object.
Specifying Keys in the jwks_object
To add more keys to or to modify keys in the JWKS (JSON Web Key Set) object, edit the JWT configuration object. In the generate object and for issuers in the validate object, add your JSON Web Keys to the array of keys in the jwks_object field.
Specifying a KeyStore in the jwks_keystore
To specify an external KeyStore as the source for the JWKS, update the subfields of the jwks_keystore field in the generate object and for issuers in the validate object. See JWT Configuration Object Fields for a detailed description of expected values in the subfields of the jwks_keystore field.
Specifying a URL in jwks_uri or in jwks_uris
Only use the jwks_uri or the jwks_uris field when you have public keys for an asymmetric algorithm. Assign a server URL to the jwks_uri field, or add a server URL into the jwks_uris array, for issuers in the validate object. The server returns a set of public keys (JWK set) for JWT validation.
Rotating Private Keys for JWT Generation
If you use an external keystore, you can automate the update of the private keys used for JWT generation. When the API Server generates a JWT, it first checks the jwks_cache_refresh_interval. If the JWKS cache is stale, the API Server updates the cache from the keystore. Since no generate.kid is specified in the keystore, the Server looks for the first private key in the JWKS cache that matches generate.algorithm. The API Server then sets the kid attribute of the generated JWT header to be the alias of this private key. This mechanism allows you to rotate keys during token generation.
To automatically rotate the private keys for JWT generation:
Remove the old private key from the external keystore and add the new one.
Do not specify the generate.kid field in jwt_config.
Use the jwks_keystore field specified in the generate section of jwt_config to specify the path to the key storage that contains the private key. When a key is fetched from a keystore, the alias of the key is the key id for the generated JWT.
Set the jwks_cache_refresh_interval field in the generate object of jwt_config. See generate Fields.
Rotating Public Keys for JWT Validation
If you use an external URI as the source for your public keys, you can automate the update of the public keys used for JWT validation. To find the right key in the JWKS for JWT validation, the API Server first looks at the key id in the JWT header. If the key id is not there, then the API Server downloads the keys from the location specified in jwks_uri or from the locations specified in jwks_uris and updates the cached JWK set. This mechanism allows you to rotate keys during token validation.
To automatically rotate the public keys for JWT validation:
Set the jwks_uri or the jwks_uris field in the validate section of jwt_config for your issuer.
If your JWT header can include the key id, then add a new key and new key id at one of the endpoints given in the jwks_uri or the jwks_uris field. The JWT headers of all new JWTs must be signed with this new key and new key id.
The approach above is the recommended approach for rotating public keys. If your JWT header cannot include the key id, do the following instead:
Set the jwks_cache_refresh_interval field in the validate object of jwt_config. See validate Fields.
Exporting a JWT Configuration Object
This section provides instructions using either the Admin Console or nnl-mgmt.sh to export the Default JWT Config or the JWT configuration object from any API Server plugin. For details about nnl-mgmt.sh's apiserver export command, see subsection Export in API Server Configuration Commands.
Note: When you export a JWT Configuration Object, the private keys are obscured. When you import the modified JWT Configuration Object back into the API Server, the obscured keys are skipped and the corresponding keys from the existing JWT Configuration Object are preserved.
Default JWT Config
The Default JWT Config is defined on the API Server's Main object.
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > Main.
Click the label Default JWT Config label.
.png?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
The Admin Console displays jwt_config in a dialog. Copy and save the contents to a file.
Using nnl-mgmt.sh
The command below exports the Default JWT Config from the default tenant's Main object into the file jwtconfig.json.
./nnl-mgmt.sh apiserver export -tenantid default -type Main -name jwt_config -file jwtconfig.jsonJWT Processor Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > Session Plugins.
Click the Modify icon for JWT Processor.
.jpg?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
The Admin Console displays the jwt_config object for the JWT Processor. Copy and save the contents to a file.
Using nnl-mgmt.sh
The example below shows how to export the JWT Processor plugin's jwt_config from the default tenant into the file my_jwt_config.json.
./nnl-mgmt.sh apiserver export -tenantid default -type SessionPlugin -name jwt_config -file my_jwt_config.jsonTransaction Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > Transaction Plugin.
Click the edit icon for JWT Transaction Processor.
The Admin Console displays the jwt_config object for the JWT Transaction Processor. Copy and save the contents to a file.
Using nnl-mgmt.sh
The example below shows how to export the Transaction plugin's jwt_config from the Marketing tenant into the file TransJWTConfig.json.
./nnl-mgmt.sh apiserver export -tenantid Marketing -type TransactionPlugin -name jwt_config -file TransJWTConfig.jsonJWT External Authentication Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > External Authentication Plugins.
Click the Edit icon for JWT Authentication Method.
The Admin Console displays the jwt_config object for the JWT External Authentication Method. Copy and save the contents to a file.
Using nnl-mgmt.sh
The example below shows how to export the JWT External Authentication plugin's jwt_config from the Marketing tenant into the file ExtAuthJWTConfig.json.
./nnl-mgmt.sh apiserver export -tenantid Marketing -type ExternalAuthenticationPlugin -name jwt_config -file ExtAuthJWTConfig.jsonImporting a JWT Configuration Object
This section provides instructions using either the Admin Console or nnl-mgmt.sh to import a Default JWT Config or JWT configuration object into any API Server plugin. For details about nnl-mgmt.sh's apiserver import command, see subsection Import in the reference API Server Configuration Commands.
Note: When you export a JWT Configuration Object, the private keys are obscured. When you import the modified JWT Configuration Object back into the API Server, the obscured keys are skipped and corresponding keys from the existing JWT Configuration Object are preserved.
Default JWT Config
The Default JWT Config is defined on the API Server's Main object.
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > Main.
Click Upload.
.png?sv=2026-02-06&spr=https&st=2026-09-30T02%3A58%3A03Z&se=2026-09-30T03%3A46%3A03Z&sr=c&sp=r&sig=Cc2xfQ2dL3SJmPR%2F23HCa0oO4wLOi%2B6gYgYVhhszasg%3D)
The Upload configuration dialog appears, navigate to your modified jwt_config.
Using nnl-mgmt.sh
The command below imports the Default JWT Config into the NorthAmerica tenant's Main object from the file jwtconfig.json.
./nnl-mgmt.sh apiserver import -tenantid NorthAmerica -type Main -name jwt_config -file jwtconfig.json -overwrite yesJWT Processor Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Session Plugins.
Locate the JWT Processor label, click its Modify button.
On the plugin configuration page click the Import button.
The Upload configuration dialog appears, navigate to your modified jwt_config.
Using nnl-mgmt.sh
The example below imports the JWT Processor plugin's jwt_config into the NorthAmerica tenant from the file my_jwt_config.json.
./nnl-mgmt.sh apiserver import -tenantid NorthAmerica -type SessionPlugin -name jwt_config -file my_jwt_config.json -overwrite yesTransaction Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > Transaction Plugin.
Locate the JWT Transaction Processor label, click its Modify button.
On the plugin configuration page click the Import button.
The Upload configuration dialog appears, navigate to your modified jwt_config.
Using nnl-mgmt.sh
The example below imports the Transaction plugin's jwt_config into the NorthAmerica tenant from the file TransJWTConfig.json.
./nnl-mgmt.sh apiserver import -tenantid NorthAmerica -type TransactionPlugin -name jwt_config -file TransJWTConfig.json -overwrite yesJWT External Authentication Plugin
Using the Admin Console
Login to the Admin Console and, if needed, switch to the correct tenant.
Navigate to Configuration > API Server > Authentication API > External Authentications Plugins.
Locate the JWT Authentication Method label, click its Modify button.
On the plugin configuration page click the Import button.
The Upload configuration dialog appears, navigate to your modified jwt_config.
Using nnl-mgmt.sh
The example below imports the JWT External Authentication plugin's jwt_config into the NorthAmerica tenant from the file ExtAuthJWTConfig.json.
./nnl-mgmt.sh apiserver import -tenantid NorthAmerica -type ExternalAuthenticationPlugin -name jwt_config -file ExtAuthJWTConfig.json -overwrite yesRotating Keys for Your RP Servers
If you have backend servers that validate JWTs issued by the API Server, you want to avoid updating those server's JWT configuration when the API Server changes its private key. You can accomplish this by using an appropriate JWKS endpoint to implement key rotation and retrieve the new public key needed to verify the JWTs generated by the API Server.
The API server exposes the URL endpoints where the JWKS is stored. Notice that the endpoint identifies the specific tenant and API Server plugin to which it applies. Each JWKS is unique to that API Server plugin and tenant combination.
Use the HTTP GET method with an endpoint. The JWKS endpoint for each API Server plugin is shown below. <api-server> is the URL where your Nok Nok API Server is hosted.
Session plugin's JWT Processor
https://<api-server>/nnlgateway/jwks/<tenant-id>/sessionJWT External Authentication plugin
https://<api-server>/nnlgateway/jwks/<tenant-id>/externalTransaction plugin
https://<api-server>/nnlgateway/jwks/<tenant-id>/transactionEMV 3DS generator
https://<api-server>/nnlgateway/jwks/<tenant-id>/emv3ds