Generate JWT Tokens

JWT claims can be signed or encrypted or signed first and the nested JWT token encrypted. Signing the claims is used most often to secure the claims. What is known today as a JWT token is typically produced by signing the claims in a JSON format using the steps described in the JSON Web Signature specification. However, when the claims are sensitive, their confidentiality can be guaranteed by following the steps described in the JSON Web Encryption specification to produce a JWT token with the encrypted claims. Finally both the confidentiality and integrity of the claims can be further enforced by signing them first and then encrypting the nested JWT token.

SmallRye JWT project provides a JWT Build API for securing the JWT claims using all of these options.

Maven dependency

<dependency>
  <groupId>io.smallrye</groupId>
  <artifactId>smallrye-jwt-build</artifactId>
  <version>${smallrye.jwt.version}</version>
</dependency>

Create JwtClaimsBuilder and set the claims

The first step is to initialize a JwtClaimsBuilder using one of the options below and add some claims to it:

import java.util.Collections;
import io.smallrye.jwt.build.Jwt;
import io.smallrye.jwt.build.JwtClaimsBuilder;
...
// Create an empty builder and add some claims
JwtClaimsBuilder builder1 = Jwt.claims();
builder1.claim("customClaim", "custom-value").issuer("https://issuer.org");
// Or start typing the claims immediately:
// JwtClaimsBuilder builder1 = Jwt.upn("Alice");

// Builder created from the existing claims
JwtClaimsBuilder builder2 = Jwt.claims("/tokenClaims.json");

// Builder created from a map of claims
JwtClaimsBuilder builder3 = Jwt.claims(Collections.singletonMap("customClaim", "custom-value"));

// Builder created from JsonObject
JsonObject userName = Json.createObjectBuilder().add("username", "Alice").build();
JsonObject userAddress = Json.createObjectBuilder().add("city", "someCity").add("street", "someStreet").build();
JsonObject json = Json.createObjectBuilder(userName).add("address", userAddress).build();
JwtClaimsBuilder builder4 = Jwt.claims(json);

// Builder created from JsonWebToken
@Inject JsonWebToken token;
JwtClaimsBuilder builder5 = Jwt.claims(token);

The API is fluent so the builder initialization can be done as part of the fluent API sequence. The builder will also set iat (issued at) claim to the current time, exp (expires at) claim to a sum of the iat claim and smallrye.jwt.new-token.lifespan property values and jti (unique token identifier) claim if they have not already been set, so one can skip setting them when possible.

The next step is to decide how to secure the claims.

Sign the claims

The claims can be signed immediately or after the JSON Web Signature headers have been set:

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims using the private key loaded from the location set with a 'smallrye.jwt.sign.key.location' property.
// No 'jws()' transition is necessary.
String jwt1 = Jwt.claims("/tokenClaims.json").sign();

// Set the headers and sign the claims with an RSA private key loaded in the code (the implementation of this method is omitted). Note a 'jws()' transition to a 'JwtSignatureBuilder'.
String jwt2 = Jwt.claims("/tokenClaims.json").jws().keyId("kid1").header("custom-header", "custom-value").sign(getPrivateKey());

Note the alg (algorithm) header is set to RS256 by default.

Encrypt the claims

The claims can be encrypted immediately or after the JSON Web Encryption headers have been set the same way as they can be signed. The only minor difference is that encrypting the claims always requires a jwe() JwtEncryptionBuilder transition:

import io.smallrye.jwt.build.Jwt;
...

// Encrypt the claims using the public key loaded from the location set with a 'smallrye.jwt.encrypt.key.location' property.
String jwt1 = Jwt.claims("/tokenClaims.json").jwe().encrypt();

// Set the headers and encrypt the claims with an RSA public key loaded in the code (the implementation of this method is omitted).
String jwt2 = Jwt.claims("/tokenClaims.json").jwe().header("custom-header", "custom-value").encrypt(getPublicKey());

Note the alg (key management algorithm) header is set to RSA-OAEP and the enc (content encryption header) is set to A256GCM by default.

Sign the claims and encrypt the nested JWT token

The claims can be signed and then the nested JWT token encrypted by combining the sign and encrypt steps.

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims and encrypt the nested token using the private and public keys loaded from the locations set with the 'smallrye.jwt.sign.key.location' and 'smallrye.jwt.encrypt.key.location' properties respectively.
String jwt = Jwt.claims("/tokenClaims.json").innerSign().encrypt();

Fast JWT Generation

If smallrye.jwt.sign.key.location or/and smallrye.jwt.encrypt.key.location properties are set then one can secure the existing claims (resources, maps, JsonObjects) with a single call:

// More compact than Jwt.claims("/claims.json").sign();
Jwt.sign("/claims.json");

// More compact than Jwt.claims("/claims.json").jwe().encrypt();
Jwt.encrypt("/claims.json");

// More compact than Jwt.claims("/claims.json").innerSign().encrypt();
Jwt.signAndEncrypt("/claims.json");

As mentioned above, iat, exp, jti and iss claims will be added if needed.

Configuration

Smallrye JWT supports the following properties which can be used to customize the way claims are signed and encrypted:

Property Name Default Description

smallrye.jwt.encrypt.key.location

none

Location of a key which will be used to encrypt the claims or inner JWT when a no-argument encrypt() method is called.

smallrye.jwt.encrypt.key

none

Key value which will be used to encrypt the claims or inner JWT when a no-argument encrypt() method is called.

smallrye.jwt.encrypt.key.id

none

Encryption key identifier which is checked only when JWK keys are used.

smallrye.jwt.encrypt.relax-key-validation

false

Relax the validation of the encryption keys

smallrye.jwt.sign.key.location

none

Location of a key which will be used to sign the claims when either a no-argument sign() or innerSign() method is called.

smallrye.jwt.sign.key

none

Key value which will be used to sign the claims when either a no-argument sign() or innerSign() method is called.

smallrye.jwt.sign.key.id

none

Signing key identifier which is checked only when JWK keys are used.

smallrye.jwt.sign.relax-key-validation

false

Relax the validation of the signing keys

smallrye.jwt.new-token.signature-algorithm

RS256

Signature algorithm. This property will be checked if the JWT signature builder has not already set the signature algorithm.

smallrye.jwt.new-token.key-encryption-algorithm

RSA-OAEP

Key encryption algorithm. This property will be checked if the JWT encryption builder has not already set the key encryption algorithm.

smallrye.jwt.new-token.content-encryption-algorithm

A256GCM

Content encryption algorithm. This property will be checked if the JWT encryption builder has not already set the content encryption algorithm.

smallrye.jwt.new-token.lifespan

300

Token lifespan in seconds which will be used to calculate an exp (expiry) claim value if this claim has not already been set.

smallrye.jwt.new-token.issuer

none

Token issuer which can be used to set an iss (issuer) claim value if this claim has not already been set.

smallrye.jwt.new-token.audience

none

Token audience which can be used to set an aud (audience) claim value if this claim has not already been set.

smallrye.jwt.new-token.override-matching-claims

false

Override the existing iss or aud claim values if smallrye.jwt.new-token.issuer or smallrye.jwt.new-token.audience properties are set.

smallrye.jwt.keystore.type

JKS

This property can be used to customize a keystore type if either smallrye.jwt.sign.key.location or smallrye.jwt.encrypt.key.location or both of these properties point to a KeyStore file. If it is not set then the file name will be checked to determine the keystore type before defaulting to JKS.

smallrye.jwt.keystore.provider

This property can be used to customize a KeyStore provider if smallrye.jwt.sign.key.location or smallrye.jwt.encrypt.key.location point to a KeyStore file.

smallrye.jwt.keystore.password

Keystore password. If smallrye.jwt.sign.key.location or smallrye.jwt.encrypt.key.location point to a KeyStore file then this property has be set.

smallrye.jwt.keystore.encrypt.key.alias

This property has to be set to identify a public encryption key which will be extracted from KeyStore from a matching certificate if smallrye.jwt.encrypt.key.location points to a KeyStore file.

smallrye.jwt.keystore.sign.key.alias

This property has to be set to identify a private signing key if smallrye.jwt.sign.key.location points to a KeyStore file.

smallrye.jwt.keystore.sign.key.password

This property may be set if a private signing key’s password in KeyStore is different to smallrye.jwt.keystore.password when smallrye.jwt.sign.key.location points to a KeyStore file.