Spring Boot Token based Authentication with Spring Security & JWT

Overview of Spring Boot JWT Authentication example

We will build a Spring Boot application in that:

  • User can signup new account, or login with username & password.

  • By User’s role (admin, moderator, user), we authorize the User to access resources

These are APIs that we need to provide:

Methods

Urls

Actions

POST

/api/auth/signup

signup new account

POST

/api/auth/signin

login an account

GET

/api/test/all

retrieve public content

GET

/api/test/user

access User’s content

GET

/api/test/mod

access Moderator’s content

GET

/api/test/admin

access Admin’s content

The database we will use could be PostgreSQL or MySQL depending on the way we configure project dependency & datasource.

Spring Boot Signup & Login with JWT Authentication Flow

The diagram shows flow of how we implement User Registration, User Login and Authorization process.

spring-boot-authentication-jwt-spring-security-flow

A legal JWT must be added to HTTP Authorization Header if Client accesses protected resources.

Spring Boot Server Architecture with Spring Security

You can have an overview of our Spring Boot Server with the diagram below:

spring-boot-authentication-spring-security-architecture

Now I will explain it briefly.

Spring Security

– WebSecurityConfigurerAdapter is the crux of our security implementation. It provides HttpSecurity configurations to configure cors, csrf, session management, rules for protected resources. We can also extend and customize the default configuration that contains the elements below.

– UserDetailsService interface has a method to load User by username and returns a UserDetails object that Spring Security can use for authentication and validation.

– UserDetails contains necessary information (such as: username, password, authorities) to build an Authentication object.

– UsernamePasswordAuthenticationToken gets {username, password} from login Request, AuthenticationManager will use it to authenticate a login account.

– AuthenticationManager has a DaoAuthenticationProvider (with help of UserDetailsService & PasswordEncoder) to validate UsernamePasswordAuthenticationToken object. If successful, AuthenticationManager returns a fully populated Authentication object (including granted authorities).

– OncePerRequestFilter makes a single execution for each request to our API. It provides a doFilterInternal() method that we will implement parsing & validating JWT, loading User details (using UserDetailsService), checking Authorizaion (using UsernamePasswordAuthenticationToken).

– AuthenticationEntryPoint will catch authentication error.

Repository contains UserRepository & RoleRepository to work with Database, will be imported into Controller.

Controller receives and handles request after it was filtered by OncePerRequestFilter.

– AuthController handles signup/login requests

– TestController has accessing protected resource methods with role based validations.

Technology

  • Java 8

  • Spring Boot 2.1.8 (with Spring Security, Spring Web, Spring Data JPA)

  • jjwt 0.9.1

  • PostgreSQL/MySQL

  • Maven 3.6.1

Project Structure

This is folders & files structure for our Spring Boot application:

spring-boot-authentication-spring-security-project-structure

security: we configure Spring Security & implement Security Objects here.

  • WebSecurityConfig extends WebSecurityConfigurerAdapter

  • UserDetailsServiceImpl implements UserDetailsService

  • UserDetailsImpl implements UserDetails

  • AuthEntryPointJwt implements AuthenticationEntryPoint

  • AuthTokenFilter extends OncePerRequestFilter

  • JwtUtils provides methods for generating, parsing, validating JWT

controllers handle signup/login requests & authorized requests.

  • AuthController: @PostMapping(‘/signin’), @PostMapping(‘/signup’)

  • TestController: @GetMapping(‘/api/test/all’), @GetMapping(‘/api/test/[role]’)

repository has intefaces that extend Spring Data JPA JpaRepository to interact with Database.

  • UserRepository extends JpaRepository<User, Long>

  • RoleRepository extends JpaRepository<Role, Long>

models defines two main models for Authentication (User) & Authorization (Role). They have many-to-many relationship.

  • User: id, username, email, password, roles

  • Role: id, name

payload defines classes for Request and Response objects

We also have application.properties for configuring Spring Datasource, Spring Data JPA and App properties (such as JWT Secret string or Token expiration time).

Setup new Spring Boot project

Use Spring web tool or your development tool (Spring Tool Suite, Eclipse, Intellij) to create a Spring Boot project.

Then open pom.xml and add these dependencies:

We also need to add one more dependency. – If you want to use PostgreSQL:

– or MySQL is your choice:

Configure Spring Datasource, JPA, App properties

Under src/main/resources folder, open application.properties, add some new lines.

For PostgreSQL

For MySQL

Create the models

We’re gonna have 3 tables in database: users, roles and user_roles for many-to-many relationship.

Let’s define these models. In models package, create 3 files:

ERole enum in ERole.java. In this example, we have 3 roles corresponding to 3 enum.

Role model in Role.java

User model in User.java. It has 5 fields: id, username, email, password, roles.

Implement Repositories

Now, each model above needs a repository for persisting and accessing data. In repository package, let’s create 2 repositories.

UserRepository

There are 3 necessary methods that JpaRepository supports.

RoleRepository

This repository also extends JpaRepository and provides a finder method.

Configure Spring Security

In security package, create WebSecurityConfig class that extends WebSecurityConfigurerAdapter.

WebSecurityConfig.java

Let me explain the code above.

– @EnableWebSecurity allows Spring to find and automatically apply the class to the global Web Security.

– @EnableGlobalMethodSecurity provides AOP security on methods. It enables @PreAuthorize, @PostAuthorize, it also supports JSR-250. You can find more parameters in configuration in Method Security Expressions.

– We override the configure(HttpSecurity http) method from WebSecurityConfigurerAdapter interface. It tells Spring Security how we configure CORS and CSRF, when we want to require all users to be authenticated or not, which filter (AuthTokenFilter) and when we want it to work (filter before UsernamePasswordAuthenticationFilter), which Exception Handler is chosen (AuthEntryPointJwt).

– Spring Security will load User details to perform authentication & authorization. So it has UserDetailsService interface that we need to implement.

– The implementation of UserDetailsService will be used for configuring DaoAuthenticationProvider by AuthenticationManagerBuilder.userDetailsService() method.

– We also need a PasswordEncoder for the DaoAuthenticationProvider. If we don’t specify, it will use plain text.

Implement UserDetails & UserDetailsService

If the authentication process is successful, we can get User’s information such as username, password, authorities from an Authentication object.

If we want to get more data (id, email…), we can create an implementation of this UserDetails interface.

security/services/UserDetailsImpl.java

Look at the code above, you can notice that we convert Set<Role> into List<GrantedAuthority>. It is important to work with Spring Security and Authentication object later.

As I have said before, we need UserDetailsService for getting UserDetails object. You can look at UserDetailsService interface that has only one method:

So we implement it and override loadUserByUsername() method.

security/services/UserDetailsServiceImpl.java

In the code above, we get full custom User object using UserRepository, then we build a UserDetails object using static build() method.

Filter the Requests

Let’s define a filter that executes once per request. So we create AuthTokenFilter class that extends OncePerRequestFilter and override doFilterInternal() method.

security/jwt/AuthTokenFilter.java

What we do inside doFilterInternal(): – get JWT from the Authorization header (by removing Bearer prefix) – if the request has JWT, validate it, parse username from it – from username, get UserDetails to create an Authentication object – set the current UserDetails in SecurityContext using setAuthentication(authentication) method.

After this, everytime you want to get UserDetails, just use SecurityContext like this:

Create JWT Utility class

This class has 3 funtions:

  • generate a JWT from username, date, expiration, secret

  • get username from JWT

  • validate a JWT

security/jwt/JwtUtils.java

Remember that we’ve added bezkoder.app.jwtSecret and bezkoder.app.jwtExpirationMs properties in application.properties file.

Handle Authentication Exception

Now we create AuthEntryPointJwt class that implements AuthenticationEntryPoint interface. Then we override the commence() method. This method will be triggerd anytime unauthenticated User requests a secured HTTP resource and an AuthenticationException is thrown.

security/jwt/AuthEntryPointJwt.java

HttpServletResponse.SC_UNAUTHORIZED is the 401 Status code. It indicates that the request requires HTTP authentication.

We’ve already built all things for Spring Security. The next sections of this tutorial will show you how to implement Controllers for our RestAPIs.

Define payloads for Spring RestController

Let me summarize the payloads for our RestAPIs: – Requests:

  • LoginRequest: { username, password }

  • SignupRequest: { username, email, password }

– Responses:

  • JwtResponse: { token, type, id, username, email, roles }

  • MessageResponse: { message }

To keep the tutorial not so long, I don’t show these POJOs here. You can find details for payload classes in source code of the project on Github.

Create Spring RestAPIs Controllers

Controller for Authentication

This controller provides APIs for register and login actions.

– /api/auth/signup

  • check existing username/email

  • create new User (with ROLE_USER if not specifying role)

  • save User to database using UserRepository

– /api/auth/signin

  • authenticate { username, pasword }

  • update SecurityContext using Authentication object

  • generate JWT

  • get UserDetails from Authentication object

  • response contains JWT and UserDetails data

controllers/AuthController.java

Controller for testing Authorization

There are 4 APIs: – /api/test/all for public access – /api/test/user for users has ROLE_USER or ROLE_MODERATOR or ROLE_ADMIN – /api/test/mod for users has ROLE_MODERATOR – /api/test/admin for users has ROLE_ADMIN

Do you remember that we used @EnableGlobalMethodSecurity(prePostEnabled = true) for WebSecurityConfig class?

Now we can secure methods in our Apis with @PreAuthorize annotation easily.

controllers/TestController.java

Run & Test

Run Spring Boot application with command: mvn spring-boot:run

Tables that we define in models package will be automatically generated in Database. If you check PostgreSQL for example, you can see things like this:

We also need to add some rows into roles table before assigning any role to User. Run following SQL insert statements:

Then check the tables:

Register some users with /signup API:

  • admin with ROLE_ADMIN

  • mod with ROLE_MODERATOR and ROLE_USER

  • zkoder with ROLE_USER

spring-boot-authentication-jwt-spring-security-signup-mod

Our tables after signup could look like this.

Access public resource: GET /api/test/all

spring-boot-authentication-jwt-spring-security-get-public-resource

Access protected resource: GET /api/test/user

spring-boot-authentication-jwt-spring-security-get-user-resource-unauthorized

Login an account: POST /api/auth/signin

spring-boot-authentication-jwt-spring-security-login-mod

Access ROLE_USER resource: GET /api/test/user

spring-boot-authentication-jwt-spring-security-get-user-resource

Access ROLE_MODERATOR resource: GET /api/test/mod

spring-boot-authentication-jwt-spring-security-get-mod-resource

Access ROLE_ADMIN resource: GET /api/test/admin

spring-boot-authentication-jwt-spring-security-get-admin-resource-unauthorized

Conclusion

Congratulation!

Today we’ve learned so many interesting things about Spring Security and JWT Token based Authentication in just a Spring Boot example. Despite we wrote a lot of code, I hope you will understand the overall architecture of the application, and apply it in your project at ease.

You can also know how to deploy Spring Boot App on AWS (for free) with this tutorial.

Happy learning! See you again.

Further Reading

Last updated

Was this helpful?