Configuration

MicroProfile JWT properties

Property Name Default Description

mp.jwt.verify.publickey

none

Public Key supplied as a string, parsed from it in the order defined in section Supported Public Key Formats.

mp.jwt.verify.publickey.location

none

Config property allows for an external or internal location of Public Key to be specified.

mp.jwt.verify.issuer

none

Expected value of the JWT iss (issuer) claim.

Supported Public Key Formats

Public Keys may be formatted in any of the following formats, specified in order of precedence:

  • Public Key Cryptography Standards #8 (PKCS#8) PEM

  • JSON Web Key (JWK) or JSON Web Key Set (JWKS)

  • Base64 URL encoded JSON Web Key (JWK) or JSON Web Key Set (JWKS)

Smallrye JWT properties

Smallrye JWT supports many properties which can be used to customize the token processing:

Property Name Default Description

smallrye.jwt.verify.key.location

NONE

Location of the verification key which can point to both public and secret keys. Secret keys can only be in the JWK format. Note that 'mp.jwt.verify.publickey.location' will be ignored if this property is set.

smallrye.jwt.verify.algorithm

RS256

Signature algorithm. Set it to ES256 to support the Elliptic Curve signature algorithm.

smallrye.jwt.verify.key-format

ANY

Set this property to a specific key format such as PEM_KEY, PEM_CERTIFICATE, JWK or JWK_BASE64URL to optimize the way the verification key is loaded.

smallrye.jwt.verify.relax-key-validation

false

Relax the validation of the verification keys, setting this property to true will allow public RSA keys with the length less than 2048 bit.

smallrye.jwt.verify.certificate-thumbprint

false

If this property is enabled then a signed token must contain either 'x5t' or 'x5t#S256' X509Certificate thumbprint headers. Verification keys can only be in JWK or PEM Certificate key formats in this case. JWK keys must have a 'x5c' (Base64-encoded X509Certificate) property set.

smallrye.jwt.token.header

Authorization

Set this property if another header such as Cookie is used to pass the token.

smallrye.jwt.token.cookie

none

Name of the cookie containing a token. This property will be effective only if smallrye.jwt.token.header is set to Cookie.

smallrye.jwt.always-check-authorization

false

Set this property to true for Authorization header be checked even if the smallrye.jwt.token.header is set to Cookie but no cookie with a smallrye.jwt.token.cookie name exists.

smallrye.jwt.token.schemes

Bearer

Comma-separated list containing an alternative single or multiple schemes, for example, DPoP.

smallrye.jwt.token.kid

none

Key identifier. If it is set then the verification JWK key as well every JWT token must have a matching kid header.

smallrye.jwt.time-to-live

none

The maximum number of seconds that a JWT may be issued for use. Effectively, the difference between the expiration date of the JWT and the issued at date must not exceed this value.

smallrye.jwt.require.named-principal

false

If an application relies on java.security.Principal returning a name then a token must have a upn or preferred_username or sub claim set. Setting this property will result in Smallrye JWT throwing an exception if none of these claims is available for the application code to reliably deal with a non-null Principal name.

smallrye.jwt.path.sub

none

Path to the claim containing the subject name. It starts from the top level JSON object and can contain multiple segments where each segment represents a JSON object name only, example: realms/subject. This property can be used if a token has no 'sub' claim but has the subject set in a different claim. Use double quotes with the namespace qualified claims.

smallrye.jwt.claims.sub

none

This property can be used to set a default sub claim value when the current token has no standard or custom sub claim available. Effectively this property can be used to customize java.security.Principal name if no upn or preferred_username or sub claim is set.

smallrye.jwt.path.groups

none

Path to the claim containing the groups. It starts from the top level JSON object and can contain multiple segments where each segment represents a JSON object name only, example: realm/groups. This property can be used if a token has no 'groups' claim but has the groups set in a different claim. Use double quotes with the namespace qualified claims.

smallrye.jwt.groups-separator

' '

Separator for splitting a string which may contain multiple group values. It will only be used if the smallrye.jwt.path.groups property points to a custom claim whose value is a string. The default value is a single space because a standard OAuth2 scope claim may contain a space separated sequence.

smallrye.jwt.claims.groups

none

This property can be used to set a default groups claim value when the current token has no standard or custom groups claim available.

smallrye.jwt.jwks.refresh-interval

60

JWK cache refresh interval in minutes. It will be ignored unless the mp.jwt.verify.publickey.location points to the HTTPS URL based JWK set and no HTTP Cache-Control response header with a positive max-age parameter value is returned from a JWK HTTPS endpoint.

smallrye.jwt.jwks.forced-refresh-interval

30

Forced JWK cache refresh interval in minutes which is used to restrict the frequency of the forced refresh attempts which may happen when the token verification fails due to the cache having no JWK key with a kid property matching the current token’s kid header. It will be ignored unless the mp.jwt.verify.publickey.location points to the HTTPS URL based JWK set.

smallrye.jwt.expiration.grace

60

Expiration grace in seconds. By default an expired token will still be accepted if the current time is no more than 1 min after the token expiry time.

smallrye.jwt.verify.aud

none

Comma separated list of the audiences that a token aud claim may contain.

smallrye.jwt.required.claims

none

Comma separated list of the claims that a token must contain.

smallrye.jwt.decrypt.key.location

none

Config property allows for an external or internal location of Private Decryption Key to be specified.

smallrye.jwt.decrypt.algorithm

RSA_OAEP

Decryption algorithm.

smallrye.jwt.token.decryption.kid

none

Decryption Key identifier. If it is set then the decryption JWK key as well every JWT token must have a matching kid header.

Create JsonWebToken with JWTParser

If the JWT token can not be injected, for example, if it is embedded in the service request payload or the service endpoint acquires it out of band, then one can use JWTParser:

import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
...
@Inject JWTParser parser;

String token = getTokenFromOidcServer();

// Parse and verify the token
JsonWebToken jwt = parser.parse(token);

You can also use it to customize the way the token is verified or decrypted. For example, one can supply a local SecretKey:

import javax.crypto.SecretKey;
import javax.ws.rs.GET;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
import io.smallrye.jwt.build.Jwt;

@Path("/secured")
public class SecuredResource {
 @Inject JWTParser parser;
 private SecretKey key = createSecretKey();

 @GET
 @Produces("text/plain")
 public Response getUserName(@CookieParam("jwt") String jwtCookie) {
    Response response = null;
    if (jwtCookie == null) {
        String newJwtCookie = Jwt.upn("Alice").sign(key);
        // or newJwtCookie = Jwt.upn("alice").encrypt(key);
        return Response.ok("Alice").cookie(new NewCookie("jwt", newJwtCookie)).build();
    else {
        // All mp.jwt and smallrye.jwt properties are still effective, only the verification key is customized.
        JsonWebToken jwt = parser.verify(jwtCookie, key);
        // or jwt = parser.decrypt(jwtCookie, key);
        return Response.ok(jwt.getName()).build();
    }
}

Token Decryption

If your application needs to accept the tokens with the encrypted claims or with the encrypted inner signed claims then all you have to do is to set smallrye.jwt.decrypt.key-location pointing to the decryption key.

If this is the only key property which is set then the incoming token is expected to contain the encrypted claims only. If either mp.jwt.verify.publickey or mp.jwt.verify.publickey.location verification properties are also set then the incoming token is expected to contain the encrypted inner-signed token.

See Generate JWT tokens and learn how to generate the encrypted or inner-signed and then encrypted tokens fast.

Custom Factories

io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory is used by default to parse and verify JWT tokens and convert them to JsonWebToken principals. It uses MP JWT and smallrye-jwt properties listed in the Configuration section to verify and customize JWT tokens.

If you need to provide your own factory, for example, to avoid verifying the tokens again which have already been verified by the firewall, then you can either use a ServiceLoader mechanism by providing a META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory resource or simply have an Alternative CDI bean implementation like this one:

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.annotation.Priority;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTAuthContextInfo;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory;
import io.smallrye.jwt.auth.principal.ParseException;

@ApplicationScoped
@Alternative
@Priority(1)
public class TestJWTCallerPrincipalFactory extends JWTCallerPrincipalFactory {

    @Override
    public JWTCallerPrincipal parse(String token, JWTAuthContextInfo authContextInfo) throws ParseException {
        try {
            // Token has already been verified, parse the token claims only
            String json = new String(Base64.getUrlDecoder().decode(token.split("\\.")[1]), StandardCharsets.UTF_8);
            return new DefaultJWTCallerPrincipal(JwtClaims.parse(json));
        } catch (InvalidJwtException ex) {
            throw new ParseException(ex.getMessage());
        }
    }
}