Using microservices you often need an adapted security implementation. One of the most adapted and scaling solution is based on JWT tokens. As a quick reminder it is a way to store some (not sensitve) data - a.k.a. security context - and only require consumers to validate a signature. Direct implication, and why it fits well microservices, is that you can generally bypass remote calls once the token is issued (until the renewal).

Microprofile provides a standard API of the consumer of JWT. It integrates with the standard @RolesAllowed API but also provide a programmatic solution integrated with CDI. You can inject a JsonWebToken and from there, access the claims of the authenticated entity. The access guarantees the token is valid (right issuer, not expired, the signature is valid etc...).

However, Microprofile does not aim to provide a JWT generator (server) since it is very dependent on the use cases and would likely lead to specifying a product and not an API so it is a bit out of scope.

Therefore, when you choose to use that technology, you will need:

  1. To implement a server (generally an OAuth2 server issuing JWT for its access tokens),
  2. To ensure your JWT are compatible with Microprofile implementations.

I will not cover the first point in this post since the generation is now quite simple with Java Base64 and Signature API - or alternatively with a library like jjwt doing that for you.

The second part is what we will cover in this post.

The first thing to validate the compatibility of your tokens with Microprofile stack is to bring back a Microprofile JWT Auth implementation. To do that you can import Geronimo one:

<dependency>
  <groupId>org.apache.geronimo</groupId>
  <artifactId>geronimo-jwt-auth</artifactId>
  <version>1.0.2</version>
  <scope>test</scope>
</dependency>

As you can see, I used the scope test since it will only be useful to validate our token creator and shouldn't be needed at runtime.

Once you have it you can use its JwtParser class to ensure your token is parseable for Microprofile specification. It will require you to start a CDI container and deploy at least geronimo-jwt-auth but you can also deploy it next to your application. Assuming you have a TokenCreator CDI bean to generate your tokens and you use Apache Meecrowave to test your code in a CDI container - you can replace it with any way to start/stop a CDI container - then we can write this test:

@MonoMeecrowaveConfig // 1
class TokenCreatorTest {
    @Inject // 2
    private TokenCreator creator;

    @Inject // 3
    private JwtParser parser;

    @Test
    void validate() {
        final String token = creator.newToken("foo", "Foo Bar"); // 4

        final JsonWebToken jsonWebToken = parser.parse(token); // 5

        // 6
        assertEquals("http://company.com/oauth2", jsonWebToken.getIssuer());

        final JsonObject custom = jsonWebToken.getClaim("custom");
        assertEquals("foo", custom.getString("name"));
        assertEquals("Foo Bar", custom.getString("displayName"));
    }
}
  1. We start/stop the cdi container and inject CDI beans in the test class through Meecrowave JUnit 5 extension,
  2. We inject our token generator - server code,
  3. We inject Geronimo JWT Auth JWT parser,
  4. We call our server logic to generate a JWT,
  5. We use Geronimo to parse the token and load its Microprofile model,
  6. From there we can validate the JWT has the expected shape.

Just reading this test it looks like it just decode the base64 segments of the JWT and loads JsonObject from there. It is actually not the case and you can write way more validations since it validates the expiration, it validates the signature - don't forget to configure it before running the test, personally I set the test pem in system properties, check out the available configuration in the project README.

This code is very simple and does not pollute your test classpath since Apache Geronimo JWT Auth does not need more than CDI, Microprofile JWT Auth and JSON API.

Doing this kind of test you guarantee that your token creator is compatible with Microprofile without much effort which is important to ensure the fast adoption of your server and to avoid to write specific code to consume them.

From the same author:

In the same category: