Simple authentication with Spring Boot and JWT Tokens

In the following article I am going to prove how you can secure a REST API (developed with Spring Boot) with JWT tokens. For simplicity Spring Security will not be used.

It is assumed the reader is already familiar with JWT.

Our Rest API will contain 3 endpoints, 2 public and 1 private (that can only be accepted with JWT):

  • /api/public/hello/{name} : Public web service that prints hello.
  • /api/secure/hello/{name} : Private web service that prints hello. Can only be called if the JWT token exist on the header. Otherwise returns HTTP 403.
  • /api/public/auth/ : Authentication service. Based on user/pass credentials generates and valid JWT token.

All the code is available on github:

Project is bootstrapped using Spring Initialzr together with gradle.

The generated build.gradle file is:

Observations:

  • The library that coverts the JWT functionality is called jjwt.
  • I prefer to use project lombok in my projects. It’s an useful library that can generate getters, setters, constructors, etc. through @Annotations.

We will be starting the project by defining some of the constants. A good idea is to store them in the application.properties file, so we can easily inject them at runtime using @Value annotation.

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

The corresponding JwtUser class will look like this:

It’s mandatory not to store important user information in the generated jwt token.

So that’s why I prefer to create a simple Pojo: JwtUser where only basic, non-sensitive information will be kept.

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 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 (I repeat) 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.

4 thoughts to “Simple authentication with Spring Boot and JWT Tokens”

  1. How to invalidate or delete JWT tokens after it generated.
    Because if user signout we need to remove or invalidate the JWT token. So how to do it.

    I tried to set expiring date to existing date but it does not work.

    1. I think there is no such thing as “Invalidation” for JWT tokens. They are stateless so in reality there is no real “sign in” nor “sign out” so the way to implement a “sign out” is as simple as delete the saved token in client-side, so the user will need to sign in again, to get the token. If it is not expired yet, the token will remain the same, but the user has signed in again.

Leave a Reply

Your email address will not be published. Required fields are marked *

Are we human, or are we dancer *