Contents

Overview

JSON Web Tokens (JWT) are an open, industry standard (RFC 7519) method for representing claims securely between two parties.

JSON Web Token defines a compact and self-contained way for securely transmitting information between parties as a JSON object. With JWT Auth you can integrate security features such as single sign on into your Helidon MP applications.

Maven Coordinates

To enable JWT Authentication, either add a dependency on the helidon-microprofile bundle or add the following dependency to your project’s pom.xml (see Managing Dependencies).

<dependency>
    <groupId>io.helidon.microprofile.jwt</groupId>
    <artifactId>helidon-microprofile-jwt-auth</artifactId>
</dependency>

Usage

The main configuration point for JWT Auth is a JAX-RS Application class. As this class is discovered using CDI, it must have a bean defining annotation.

Minimal required setup is done using @LoginConfig(authMethod = "MP-JWT"):

@LoginConfig(authMethod = "MP-JWT")
@ApplicationScoped
public class ProtectedApplication extends Application {
}

API

The following interfaces and annotations are used to work with JWT in Helidon MP:

  • JsonWebToken - an interface used in CDI beans (@RequestScoped) dependency injection to obtain the JWT of the currently executing caller.

  • @Claim - an annotation used by CDI bean (@RequestScoped) dependency injection to obtain individual claims from the caller’s JWT.

  • ClaimValue - a proxy interface used with @Claim annotation to оbtain the value of a claim by calling getValue().

Configuration

MP-JWT Auth configuration is defined by the spec (options prefixed with `mp.jwt.`), and we add a few configuration options for the security provider (options prefixed with `security.providers.mp-jwt-auth.`)

Configuration options

Table 1. Optional configuration options
key type default value description

mp.jwt.decrypt.key.algorithm

string (RSA-OAEP, RSA-OAEP-256)

 

Expected key management algorithm supported by the MP JWT endpoint. Supported algorithms are either RSA-OAEP or RSA-OAEP-256. If no algorithm is set, both algorithms must be accepted.

Allowed values:

  • RSA-OAEP: RSA-OAEP Algorithm

  • RSA-OAEP-256: RSA-OAEP-256 Algorithm

mp.jwt.decrypt.key.location

string

 

Private key for decryption of encrypted claims. The value may be a relative path or a URL.

mp.jwt.token.cookie

string

Bearer

Specific cookie property name where we should search for JWT property.

mp.jwt.token.header

string

Authorization

Name of the header expected to contain the token.

mp.jwt.verify.audiences

string[]

 

Expected audiences of incoming tokens.

mp.jwt.verify.clock.skew

int

5

Clock skew to be accounted for in token expiration and max age validations in seconds.

mp.jwt.verify.issuer

string

 

Expected issuer in incoming requests.

mp.jwt.verify.publickey

string

 

String representation of the public key.

mp.jwt.verify.publickey.location

string

 

Path to public key. The value may be a relative path or a URL.

mp.jwt.verify.token.age

int

 

Maximal expected token age in seconds. If this value is set, iat claim needs to be present in the JWT.

security.providers.mp-jwt-auth.allow-impersonation

boolean

false

Whether to allow impersonation by explicitly overriding username from outbound requests using io.helidon.security.EndpointConfig.PROPERTY_OUTBOUND_ID property. By default this is not allowed and identity can only be propagated.

security.providers.mp-jwt-auth.atn-token.default-key-id

string

 

Default JWT key ID which should be used.

security.providers.mp-jwt-auth.atn-token.handler

 

Token handler to extract username from request. Uses Authorization header with `bearer ` prefix by default.

security.providers.mp-jwt-auth.atn-token.jwk.resource

 

JWK resource for authenticating the request

security.providers.mp-jwt-auth.atn-token.jwt-audience

string

 

Audience expected in inbound JWTs.

security.providers.mp-jwt-auth.atn-token.verify-key

string

 

Path to public key. The value may be a relative path or a URL.

security.providers.mp-jwt-auth.authenticate

boolean

true

Whether to authenticate requests.

security.providers.mp-jwt-auth.load-on-startup

boolean

false

Whether to load JWK verification keys on server startup Default value is false.

security.providers.mp-jwt-auth.optional

boolean

false

Whether authentication is required. By default, request will fail if the username cannot be extracted. If set to false, request will process and this provider will abstain.

security.providers.mp-jwt-auth.principal-type

SubjectType (USER, SERVICE)

USER

Principal type this provider extracts (and also propagates).

security.providers.mp-jwt-auth.propagate

boolean

true

Whether to propagate identity.

security.providers.mp-jwt-auth.sign-token

 

Configuration of outbound rules.

A configuration example in microprofile-config.properties:

mp.jwt.verify.issuer=https://{PublicIssuerDomain}/oauth2/default
mp.jwt.verify.publickey.location=${mp.jwt.verify.issuer}/v1/keys

Examples

@Path("/hello")
public class HelloResource {

    @GET
    @Produces(TEXT_PLAIN)
    public String hello(@Context SecurityContext context) {
        Optional<Principal> userPrincipal = context.userPrincipal();
        return "Hello, " + userPrincipal.get().getName() + "!";
    }
}

Do not forget to annotate the HelloApplication class to enable JWT:

@LoginConfig(authMethod = "MP-JWT")
@ApplicationScoped
public class HelloApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        return Set.of(HelloResource.class);
    }
}

Add the following configuration in microprofile-config.properties:

mp.jwt.verify.issuer=https://{IssuerPublicDomain}/oauth2/default
mp.jwt.verify.publickey.location=${mp.jwt.verify.issuer}/v1/keys

Obtain the Security Token from external issuer:

TOKEN=sdf4dDSWFcswdsffDSasEgv...

Run the application and execute an http request against it:

curl -X GET -I -H "Authorization: Bearer $TOKEN" http://localhost:8080/hello
Curl output
HTTP/1.1 200 OK
Date: 08.06.2022 10:33:47 EEST
connection: keep-alive
content-length: 28

Hello, secure@helidon.io!

which means that the request successfully passed authentication.

Additional Information

Learn more about JWT authentication at:
Eclipse MicroProfile Interoperable JWT RBAC

Reference