If you ever wanted to secure your brilliant REST API with Spring Boot but Spring Security felt too confusing, badly documented and a little overkill for the simple stuff you want to do, you can create a simple, stateless, authentication mechanism for your services using JWT Tokens.

As a proof of concept on how we are going to integrate the JWT tokens with our Spring Boot Rest api we are going to create three REST services:

  • /api/public/hello/{name} : This will be a public web service that will say hello without discrimination;
  • /api/secure/hello/{name} : This will perform the same operation as the service above, but it will be callable only by authenticated users. Otherwise it will return 401 Unauthorised. Or 406 Not Acceptable if somebody is trying to hack into your tokens :);
  • /api/public/auth/ : This service will allow the users of your API to authenticate with it.

The code can be found also on github:

Our project will be built using Spring Initialzr together with gradle. Our build.gradle file for the project will eventually look like this.

Observations:

  • The library that implements the JWT part is called jjwt and can be found here.
  • I prefer to use project lombok in my projects. It’s a cool little library that generates getters/setters/constructors/builders and other neat stuff through the use of annotations.

A good idea for the project is to keep some of the configurable properties like the time to live for the token, the authentication header and the secret key in the Spring Boot application.properties file.

They can easily be “injected” in our code at a later time using the @Value annotation.

The next step is to actually define the JwtService that will be responsible with the creation / decomposition of the token.

The corresponding JwtUser class will look like this:

It’s important not to store important user information in the generated jwt token. So that’s why I prefer to create a simple Pojo, JwtUser where I’ll keep on the most important, non-sensitive user information.

Don’t get discouraged by the @Data, @NoArgsConstructor and @AllArgsConstructor annotations. They are part from Project Lombok, and basically they are generators for Setters, Getters and Constructors.

From the above service we will use the getToken and the getUser methods. The first one, will use the encoded secret key and the expiration time (the properties that were mentioned in the application.properties file) in order to generate an unique jwt token.

This token will be returned to the user after he authenticates. Then the user needs to adds to add this token as an ‘x-auth-token’ (the HTTP Header defined as jwt.auth.header in application.properties) if he wants to access the services that are under /api/secure*.

To implement the authentication feature we can add a new Spring @Service called UserService:

As you can see we use another model called User (not JwtUser) to work with our internal data. Important to notice that the bean JwtUser will only be used as payload information for the jwt token. The User bean can contain critical information that we shouldn’t not expose on the web.

The User class looks like this:

Everything is now managed in at the controller level. In our simple case the orchestration is done at the @RestController level. In real-world application this should be done in the Service layer.

The HelloJWT controller may look like this:

And now comes the most interesting part.

For each HTTP Request that goes under /api/secure* we need to configure a @WebFilter that will be responsible to verify if that request contains the desired HTTP Header containing a valid jwt token. In the contrary case the request will be rejected and the web service mapped at that url will not be accessed.

This the code for the JwtFilter.

An additional configuration should be done. In order for Spring Boot to scan the @WebFilter component we need to use the @ServletComponentScan annotation to target the java package where we created our class.

This is how our main class looks like:

By default the application should run on http://localhost:8080.

So if we hit the public api (localhost:8080/api/public/hello/andrei) we will receive the desire result:

Public-API-JWT

But if we want to hit the secure api at http://localhost:8080/api/secure/hello/andrei our request will be rejected:

jwt-hit-2-secure

So in order to obtain the code we will need to first call the authentication service at http://localhost:8080/api/public/auth with the correct body:

jwt-auth-request

As you can see the authentication was correct and the response contains the JWT token.

Now we want to access the secure resource we just copy/paste this JWT token as the auth header and we will be able to access the /secure/* api:

4

As you can see everything is working just as expected.

Thank you for reading.

Leave a reply

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url=""> 

required

Are we human, or are we dancer *