A blog mainly about Java

Securing JAX-RS Endpoints with JWT

In this blog post I’ll show you how to use the JJWT library to issue and verify JSon Web Tokens with JAX-RS endpoints. The idea is to allow an invocation when no token is needed, but also, be able to reject an invocation when a JWT token is explicitly needed.

Let’s say we have a REST Endpoint with several methods: methods that can be invoked directly, and methods that can be invoked only if the caller is authenticated. There are several ways to authenticate, authorize, encrypt… REST endpoints invocations. Some complex, some easier. Here I will use JWT, or JSon Web Token. The idea is that when authorization is needed, the caller needs to get a JWT token and then pass it around. I won’t go into too much details on JSon Web Token as you can find plenty of resources. I just want to show you some code so you see how easy it is to setup with JAX-RS.

Use Case

In this example we have two REST Endpoints:

EchoEndpoint: this is just a Echo endpoint with two methods: one accessible by everyone (echo), another one accessible only if you pass a valid JSon Web Token (echoWithJWTToken), meaning you identified first using UserEndpoint

UserEndpoint: this endpoint returns information about the users of the application(the User JPA entity), but more important, has a method to authenticate (authenticateUser) using login/password. Once authenticate, you get a JSon Web Token (and can then pass it around)

Securing an Invocation

Below is the code of the EchoEndpoint. As you can see, this basic JAX-RS Endpoint has two GET methods both returning a String:

one on /echo accessible by everyone

one on /echo/jwt only accessible if the client passes a token. How do we check that the token is needed? Using the JWTTokenNeededname binding and the JWTTokenNeededFilter (see below)

Filter Checking the JSon Web Token

The magic hides behind JWTTokenNeeded. Well, not really, it hides behind the JWTTokenNeededFilter. JWTTokenNeeded is just a JAX-RS name binding (think of it as a CDI interceptor binding), so it’s just an annotation that binds to a filter.

The filter itself is the one doing all the work. It implements ContainerRequestFilter and therefore allows us to check the request headers. Basically, when the EchoEndpoint::echoWithJWTToken method is invoked, the runtime intercepts the invocation, and does the following:

Gets the HTTP Authorization header from the request and checks for the JSon Web Token (the Bearer string)

As you can see on line 22, the JJWT library is very simple as it checks if the token is valid in only 1 line. Validation is made depending on a Key. Here I just use a String to make the example easy to understand, but it could be something safer, like a keystore.

Issuing a JSon Web Token

Ok, now we have a filter that checks that the token is passed in the HTTP header. But how is this token issued? The user needs to login, invoking an HTTP POST and passing a login and password (here, login and password are passed in clear for sake of simplicity, but this part should use HTTPs). Once authenticated, JJWT is used to create a token based on the users’ login and the secret key (the same key used in JWTTokenNeededFilter).

Notice that the JSon Web Token sets a few claims (in the issueToken method): subject (the principal’s login), a issuer (the one who issued the token), an issued date, a signing algorithm, and very important, an expiration date for the token. Now, the client is authenticated, and it has a token that it needs to pass to be able to invoke the Echo endpoint again.

Conclusion

In this blog I wanted to show you how easy it is to issue and validate a JSon Web Token withJAX-RS. Here I’m using the external JJWT library as this is not standard in JAX-RS. I find JJWT easy to use but you can find other librairies that do more or less the same (jose.4.j, Nimbus or Java JWT). I didn’t use any security for authentication (security is complex and not very portable in Java EE) so the login/password are not encrypted and no realm is setup.

Related

Post navigation

I’m the creator of the pac4j security engine (http://www.pac4j.org) and in my case, I have authenticated user profiles (with attributes) I want to turn into JWTs to call web services, so I need encryption to protect the personal data of these profiles.

And JJWT does not support encryption while the Nimbus library (which is for me the best choice) supports it.

“security is complex and not very portable in Java EE”: I could not agree more, this is exactly the idea behind pac4j: make security easy and portable across Java frameworks and we have implementations for J2E, Spring MVC, Spring Security, Vertx, Play and many more.

Hi Antonio!
Too bad the interview didn’t work out, but did have fun doing it 🙂 (@JCrete2015)
I have 2 comments re JWTTokenNeededFilter.
In line 17 I’d do a “Bearer “.length() and no .trim().
Second, 401 is for Basic Authentication afaik, I’d use 403 Forbidden instead.
Cheers
Jesper

Hi,
I am using most of this tutorial code to Create JWT and validate in subsequent request whether token exist. If exist then authorized else redirect to login. I am able to create token but not able to get back it in JWTTokenNeededFilter from ContainerRequestContext. As String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); I am getting null, no token set here. So I am saving the token to browser cookie now. But again failed to get in back here. Also using @cookieParam gettinig exception. Any help will be great for me. Thank in advance.

In your code inside filter() method, you’re generating a new signing key when validating an existing token. Shouldn’t this key be a key that was used for issuing a token? Is this code correct or is it meant to be replaced?