back to all blogsSee all blog posts

MicroProfile JSON Web Token 1.2

image of author
Adam Yoho on Mar 26, 2021

The MicroProfile JWT specification allows you to use a JSON Web Token (JWT) for authenticating and authorizing requests to a service. The latest version of the specification simplifies the configuration for managing the validation of the JWT by introducing new MicroProfile Config properties. Support for JSON Web Encryption (JWE) tokens and new signature algorithms are also added in this feature.

The full specification can be found here: MicroProfile Interoperable JWT RBAC 1.2.

The following sections describe the different features that are added with MicroProfile JWT version 1.2:

New MP Config properties

Version 1.2 of the MicroProfile JWT specification adds the following MicroProfile Config properties to control different aspects of JWT validation.

Note: If you do not wish to use MicroProfile Config properties, the <mpJwt> element in Open Liberty’s server.xml file provides equivalent functionality for each of these properties. Whenever there is an equivalent attribute in the server.xml file for an MP Config property, the attribute in the server.xml file takes precedence if configured.

mp.jwt.token.header

The mp.jwt.token.header property allows you to control the HTTP request header that is expected to contain a JWT. You can specify either "Authorization" (default) or "Cookie".

The token header can also be configured in the tokenHeader attribute of the <mpJwt> element in the server.xml file:

<mpJwt id="myMpJwt" tokenHeader="Authorization" ... />

The mp.jwt.token.cookie property allows you to specify the name of the cookie that is expected to contain a JWT. The default value is "Bearer" if not specified.

The token cookie name can also be configured in the cookieName attribute of the <mpJwt> element in the server.xml file:

<mpJwt id="myMpJwt" tokenHeader="Cookie" cookieName="Bearer" ... />

Note: The mp.jwt.token.header MP Config property or tokenHeader attribute must be set to "Cookie" for the mp.jwt.token.cookie property or cookieName attribute in the server.xml file to be recognized.

mp.jwt.verify.audiences

The mp.jwt.verify.audiences property allows you to create a list of allowable audience values. At least one of these values must be found in the "aud" claim of the JWT. Previously, this had to be configured in the server.xml file. Now you can configure the audiences in the MicroProfile Config property as follows:

mp.jwt.verify.audiences=conferenceService, adminService

mp.jwt.decrypt.key.location

To support JSON Web Encryption tokens, the mp.jwt.decrypt.key.location property allows you to specify the location of the Key Management Key. This is the private key that is used to decrypt the Content Encryption Key, which is then used to decrypt the JWE ciphertext. The private key must correspond to the public key that is used to encrypt the Content Encryption Key.

mp.jwt.decrypt.key.location=/path/to/privatekey.pem

The decryption key location can also be specified by using the keyManagementKeyAlias attribute of the <mpJwt> element in the server.xml file. The value must be set to the alias for the private key in the configured keystore that should be used to decrypt the Content Encryption Key.

<mpJwt id="myMpJwt" sslRef="sslConfig" keyManagementKeyAlias="kmkAlias" ... />

<ssl id="sslConfig" keyStoreRef="myKeyStore" ... />

<!-- Keystore that contains a key with the alias "kmkAlias" to be used to decrypt the Content Encryption Key -->
<keyStore id="myKeyStore" ... />

Note: When the mp.jwt.decrypt.key.location property or keyManagementKeyAlias attribute is specified, the application will only accept tokens in JWE format; tokens in JWS format will be rejected. Inversely, if this property is not specified, the application will only accept tokens in JWS format.

Also note: The payload of JWE tokens must be a nested JWT in JSON Web Signature (JWS) format. JWE tokens that contain a payload that is not a nested JWS will be rejected.

mp.jwt.verify.publickey.algorithm

The mp.jwt.verify.publickey.algorithm property allows you to control the Public Key Signature Algorithm that is supported by the MP JWT endpoint. The default value is "RS256" if not specified. Previously, this had to be configured in the server.xml file. Now you can configure the public key algorithm that is used for verification of the JWT in the MicroProfile Config property as follows:

mp.jwt.verify.publickey.algorithm=ES256

The specification adds support for the ES256 signature algorithm, while Open Liberty also adds support for using the RS384, RS512, HS384, HS512, ES256, ES384, and the ES512 signature algorithms.

MicroProfile JWT 1.2 configuration examples

This section will demonstrate a few examples of how to use MP JWT 1.2 functionality in your web applications.

A sample application that you can try yourself is available on GitHub. The application uses the examples that are provided here and includes sample JWTs that you can use for testing. Setup takes less than 5 minutes and only requires Maven to build and run.

The server configuration and application code shown here is common to all of the ensuing examples. Application code and MP Config values are taken, and in some cases modified, from the MicroProfile JWT TCK.

Server configuration

Enabling the microProfile-4.0 convenience feature will enable MP JWT 1.2 support, as shown here:

<featureManager>
    <feature>microProfile-4.0</feature>
</featureManager>

This is the only server configuration typically necessary to use MP JWT 1.2 functionality. The mpJwt-1.2 feature can also be specified on its own if the other MicroProfile 4.0 features aren’t needed.

Application code

The snippet shown here is a JAX-RS resource that is used in all of the web applications in later examples. The original source can be found here.

import javax.annotation.security.DenyAll;
import javax.annotation.security.RolesAllowed;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;

@Path("/endp")
@DenyAll
@RequestScoped
public class RolesEndpoint {

    @GET
    @Path("/echo")
    @RolesAllowed("Echoer")
    public String echoInput(@Context SecurityContext sec, @QueryParam("input") String input) {
        Principal user = sec.getUserPrincipal();
        return input + ", user="+user.getName();
    }
}

The configuration of the resource is pretty simple. In a nutshell, this resource provides a /endp/echo endpoint that serves HTTP GET requests to users in the "Echoer" role. If authorized, the endpoint returns a string that contains the Principal name of the authenticated user alongside the value of the "input" query parameter that is sent in the request. If the user is not authorized, a 401 error will be returned.

With the mpJwt-1.2 feature enabled, authorization will be determined based on the MP JWT configuration in the server and application. Any authorized request to this endpoint must therefore include a valid JWT in accordance with the MP JWT and application configurations.

Accepting JSON Web Encryption (JWE) tokens

This example demonstrates how to configure a web application to accept JWTs in JSON Web Encryption (JWE) format.

Usage of the following MP Config properties will be demonstrated:

Note: The mp.jwt.verify.publickey.location and mp.jwt.verify.issuer properties were added by an earlier version of the MP JWT specification. There are also alternative attributes that can be specified in the server.xml file for these MP config properties.

The following MP Config source snippet shows the values for those properties:

mp.jwt.decrypt.key.location=/privateKey.pem
mp.jwt.verify.audiences=s6BhdRkqt3
mp.jwt.verify.publickey.location=/publicKey.pem
mp.jwt.verify.issuer=https://server.example.com

The mp.jwt.decrypt.key.location and mp.jwt.verify.publickey.location properties point to PEM files that are packaged within the application itself. The decrypt key is used to decrypt the JWE content. The public key is used to verify the signature of the nested JSON Web Signature (JWS) token in the payload of the JWE token. The mp.jwt.verify.audiences value is checked against the "aud" claim of the nested JWS token to ensure that the claim contains the audience value. Likewise, the mp.jwt.verify.issuer value is checked against the "iss" claim.

Submitting the request

The following shows an HTTP GET request to the /endp/echo endpoint, where <JWE> would be substituted for the JWE token string:

GET /endp/echo HTTP/1.1
Host: server.example.com
Authorization: Bearer <JWE>

input=Hello

A successfully authorized request produces the response:

HTTP/1.1 200 OK

Hello, [email protected]

A successful response means that the following details are true:

  • The JWT in the Authorization header is in JWE format.

  • The JWE content was successfully decrypted by using the privateKey.pem key packaged within the application, per the mp.jwt.decrypt.key.location MP Config property.

  • The payload of the JWE token is a nested JWS.

  • The signature of the nested JWS was successfully verified by using the publicKey.pem key packaged within the application, per the mp.jwt.verify.publickey.location MP Config property.

  • The "iss" claim of the nested JWS within the JWE token is "https://server.example.com".

  • The "aud" claim of the nested JWS within the JWE is set to, or includes, "s6BhdRkqt3".

  • The "groups" claim of the nested JWS within the JWE is set to, or includes, "Echoer".

  • The "upn" claim of the nested JWS within the JWE token is "[email protected]".

Accepting JWTs in cookies

This example demonstrates how to configure a web application to accept JWTs in a cookie instead of an HTTP request header.

Usage of the following MP Config properties will be demonstrated:

Note: The mp.jwt.verify.publickey.location and mp.jwt.verify.issuer properties were added by an earlier version of the MP JWT specification.

The following MP Config source snippet shows the values for those properties:

mp.jwt.token.header=Cookie
mp.jwt.token.cookie=jwt
mp.jwt.verify.publickey.algorithm=ES256
mp.jwt.verify.publickey.location=/publicKey.pem
mp.jwt.verify.issuer=https://server.example.com

The mp.jwt.token.header property indicates that the application expects a JWT to be passed in a cookie in inbound requests. The mp.jwt.token.cookie property specifies that the JWT will be in a cookie named "jwt". The mp.jwt.verify.publickey.algorithm property indicates that the JWS is expected to be signed with the ES256 (ECDSA using P-256 and SHA-256) signature algorithm.

The mp.jwt.verify.publickey.location and mp.jwt.verify.issuer enforce the same behavior described in the Accepting JSON Web Encryption (JWE) tokens example.

Submitting the request

The following shows an HTTP GET request to the /endp/echo endpoint, where <JWS> would be substituted for the JWS token string:

GET /endp/echo HTTP/1.1
Host: server.example.com
Cookie: jwt=<JWS>

input=Hello

A successfully authorized request produces the response:

HTTP/1.1 200 OK

Hello, [email protected]

A successful response means that the following details are true:

  • The JWS was signed with the ES256 signature algorithm, per the mp.jwt.verify.publickey.algorithm MP Config property.

  • The signature of the JWS was successfully verified by using the publicKey.pem key packaged within the application, per the mp.jwt.verify.publickey.location MP Config property.

  • The "iss" claim of the nested JWS within the JWE token is "https://server.example.com".

  • The "groups" claim of the nested JWS within the JWE is set to, or includes, "Echoer".

  • The "upn" claim of the nested JWS within the JWE token is "[email protected]".

Summary

MicroProfile JWT 1.2 has some powerful new features useful for securing cloud native applications. You can read more about these updates on the MP JWT 1.2 release page.

MicroProfile JWT 1.2 is part of the larger MicroProfile 4.0 release. If you’d like to learn more about the other technologies in MicroProfile 4.0, check out this deep dive blog post.

As always, let us know if you have any questions with this new feature. Thanks for checking it out!

Tags