# Java FullStack Spring boot & React app: Backend REST API / 3 - Securing the REST API with Spring Security & JWT (a)

Welcome back!

In the [previous tutorial](https://wilkom2009.hashnode.dev/java-fullstack-spring-boot-and-react-app-backend-rest-api-2), we have set up the CRUD operations in our REST API. In this tutorial we're going to secure the REST API using [Spring security](https://spring.io/projects/spring-security) and [Json Web Token a.k.a JWT](https://jwt.io/). Reminder : this tutorial is part of [series](https://wilkom2009.hashnode.dev/project-introduction) covering a full-stack app development.

## What we'll cover here

- How to customize Spring security to fetch users from database
- How to implement JWT token management in Spring boot REST API
- How to expose a REST POST API /login to generate a JWT token


## User entity and repository
We are going to create an enum class to manage static roles for simplicity purpose. Let's create a package: *security.model*, then, in the model package create *ERole.java* class as follow:

```
package com.codeurinfo.easytransapi.security.model;

public enum ERole {
  ROLE_ADMIN,
  ROLE_USER,
}
``` 
Here, we have two roles: ROLE_ADMIN for administrator role and ROLE_USER for a simple user role. you can add more roles as needed.

Once roles class coded, we gonna create a custom user class in the same package as ERole.java, we'll annotated it as an entity.

```
package com.codeurinfo.easytransapi.security.model;


import java.util.Objects;
import java.util.Set;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "users")
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String userName;
  private String password;
  private String name;
  @ElementCollection (targetClass = ERole.class)
  @Enumerated(EnumType.STRING)
  private Set<ERole> roles;

  public User() {}

  public User(
    String userName,
    String password,
    String name,
    Set<ERole> roles
  ) {
    this.userName = userName;
    this.password = password;
    this.name = name;
    this.roles = roles;
  }
/**
   * getters and setters
   */

``` 
*@ElementCollection* is used to map the ERole.java enum list which is not an entity while *@Enumerated(EnumType.STRING)*, especially ( * EnumType.STRING * ) tells JPA to persist Enum names instead of their index numbers in the DB.

Now, let's create the repository to manage the *User.class* in a new package : *security.repository* .

```
package com.codeurinfo.easytransapi.security.repository;

import com.codeurinfo.easytransapi.security.model.User;

import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {
  Optional<User> findByUserName(String userName);
}

``` 
*findByUserName* is a query method to fetch user by a given userName. You can read more about [Spring Data JPA query methods here](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods).

User entity is now ready to be used, in the following sections, we are going to implement very interesting spring security features.

## Dependency management
Open the pom.xml file and add following dependencies:


```
<!-- Spring security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<!-- JWT  -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt</artifactId>
			<version>0.9.1</version>
		</dependency>

		<!-- very important while using java 11 and above -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.1</version>
		</dependency>
``` 

### Customize Spring security to fetch user from DB (H2 database)
In order to use custom user management in Spring Security, we must first implement Spring security core ***UserDetails*** interface to map our custom User detail class to Spring security User class and then implement Spring security core ***UserDetailsService*** interface so that Spring can query users from the DB.

Within security package, create a class named UserDetailsImpl.java :

```
package com.codeurinfo.easytransapi.security;

import com.codeurinfo.easytransapi.security.model.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class UserDetailsImpl implements UserDetails {

  private Long id;

  private String username;

  @JsonIgnore
  private String password;

  private Collection<? extends GrantedAuthority> authorities;

  public UserDetailsImpl(
    Long id,
    String username,
    String password,
    Collection<? extends GrantedAuthority> authorities
  ) {
    this.id = id;
    this.username = username;
    this.password = password;
    this.authorities = authorities;
  }

  /**
   * Static method to expose UserDetailsImpl object created by given user
   * @param user
   * @return UserDetailsImpl object
   */
  public static UserDetailsImpl build(User user) {
    // Map user roles list to Spring Security GrantedAuthority list
    List<GrantedAuthority> authorities = List
      .copyOf(user.getRoles())
      .stream()
      .map(role -> new SimpleGrantedAuthority(role.name()))
      .collect(Collectors.toList());

    return new UserDetailsImpl(
      user.getId(),
      user.getUserName(),
      user.getPassword(),
      authorities
    );
  }

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() {
    return authorities;
  }

  public Long getId() {
    return id;
  }

  @Override
  public String getPassword() {
    return password;
  }

  @Override
  public String getUsername() {
    return username;
  }

  @Override
  public boolean isAccountNonExpired() {
    return true;
  }

  @Override
  public boolean isAccountNonLocked() {
    return true;
  }

  @Override
  public boolean isCredentialsNonExpired() {
    return true;
  }

  @Override
  public boolean isEnabled() {
    return true;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    UserDetailsImpl user = (UserDetailsImpl) o;
    return Objects.equals(id, user.id);
  }
}

``` 
Now, we can implement the UserDetailsService. Create *UserDetailsServiceImpl.java* class in *security* package as follow:

```
package com.codeurinfo.easytransapi.security;

import com.codeurinfo.easytransapi.security.model.User;
import com.codeurinfo.easytransapi.security.repository.UserRepository;
import java.util.ArrayList;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  private UserRepository userRepository;

  /**
   * Override this method to fetch user by userName from th db
   * using the UserRepository
   * @Transactional is used to manage User & roles collection lazy loading
   */
  @Override
  @Transactional
  public UserDetails loadUserByUsername(String userName) {

    User user = userRepository.findByUserName(userName).orElse(null);

    return UserDetailsImpl.build(user);
  }
}

```

### Create a JWT utility class
In the security package, create a package util and create JwtUtil.class.


```
package com.codeurinfo.easytransapi.security.util;

import com.codeurinfo.easytransapi.security.UserDetailsImpl;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.stereotype.Service;

@Service
public class JwtUtil {

  // Give a secret key for JWT token generating & validation
  private String SECRET_KEY = "secret";

  // get username from the provided token
  public String extractUsername(String token) {
    return extractClaim(token, Claims::getSubject);
  }

  //get the token expiration time
  public Date extractExpiration(String token) {
    return extractClaim(token, Claims::getExpiration);
  }

  // get token infos
  public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
    final Claims claims = extractAllClaims(token);
    return claimsResolver.apply(claims);
  }

  private Claims extractAllClaims(String token) {
    return Jwts
      .parser()
      .setSigningKey(SECRET_KEY)
      .parseClaimsJws(token)
      .getBody();
  }

  private Boolean isTokenExpired(String token) {
    return extractExpiration(token).before(new Date());
  }

  public String generateToken(UserDetailsImpl userDetails) {
    Map<String, Object> claims = new HashMap<>();
    return createToken(claims, userDetails.getUsername());
  }

  /**
   * Generate a token for the provided subject (username)
   * @param claims
   * @param subject
   */
  private String createToken(Map<String, Object> claims, String subject) {
    return Jwts
      .builder()
      .setClaims(claims)
      .setSubject(subject)
      .setIssuedAt(new Date(System.currentTimeMillis()))
      .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) //Expiration in 36,000,000 ms (10 hours)
      .signWith(SignatureAlgorithm.HS256, SECRET_KEY) // signing with HS256 algorythm
      .compact();//According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)
      //   compaction of the JWT to a URL-safe string 
  }

  /**
   * Validate token
   */
  public Boolean validateToken(String token, UserDetailsImpl userDetails) {
    final String username = extractUsername(token);

    return (
      username.equals(userDetails.getUsername()) && !isTokenExpired(token)
    );
  }
}
``` 
### Providing a /login REST API POST endpoint
In this section, we'll be coding a controller to expose an authentication endpoint to our REST API.

Let's create *AuthenticationRequest.java* class in security.model package in order to hold the username and password coming from our REST API consumer's http request payload.

```
package com.codeurinfo.easytransapi.security.model;

import java.util.Objects;

public class AuthenticationRequest {

  private String userName;
  private String password;

  public AuthenticationRequest() {}

  public AuthenticationRequest(String userName, String password) {
    this.userName = userName;
    this.password = password;
  }

 // Getters and setters

}
``` 
Create another class named *AuthenticationResponse.java* to send the response containing the JWT token to the client.


```
package com.codeurinfo.easytransapi.security.model;

import java.util.Objects;

public class AuthenticationResponse {

  private String jwt;

  public AuthenticationResponse() {}

  public AuthenticationResponse(String jwt) {
    this.jwt = jwt;
  }

  // getters and setters

``` 

To expose a** /login** endpoint that will accept an *AuthenticationRequest* object and return an AuthenticationResponse object to the client, let's create   *AuthController.java* class in the *security* package.

```
package com.codeurinfo.easytransapi;

import com.codeurinfo.easytransapi.security.UserDetailsImpl;
import com.codeurinfo.easytransapi.security.UserDetailsServiceImpl;
import com.codeurinfo.easytransapi.security.model.AuthenticationRequest;
import com.codeurinfo.easytransapi.security.model.AuthenticationResponse;
import com.codeurinfo.easytransapi.security.repository.UserRepository;
import com.codeurinfo.easytransapi.security.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AuthController {

  @Autowired
  private AuthenticationManager authenticationManager;

  @Autowired
  private UserDetailsServiceImpl userDetailsService;

  @Autowired
  private JwtUtil jwtUtil;

  @PostMapping("/api/auth/login")
  public ResponseEntity createAuthenticationToken(
    @RequestBody AuthenticationRequest request
  )
    throws Exception {
    Authentication authentication = null;
    try {
      // Use AuthenticationManager to verify the provided username/password
      authentication =
        authenticationManager.authenticate(
          new UsernamePasswordAuthenticationToken(
            request.getUserName(),
            request.getPassword()
          )
        );
    } catch (Exception exception) {
      throw new Exception("Incorrect username or password");
    }
    //if username/password valid, put the Authentication created object in the SecurityContextHolder's context
    SecurityContextHolder.getContext().setAuthentication(authentication);

    // Retrieve the user from the UserDetailsServiceImpl
    final UserDetailsImpl userDetails = (UserDetailsImpl) userDetailsService.loadUserByUsername(
      request.getUserName()
    );

    // Generate the token from the JWT util class
    String jwt = jwtUtil.generateToken(userDetails);

    // Send AuthenticationResponse response to client
    return ResponseEntity.ok(new AuthenticationResponse(jwt));
  }
}

``` 

We can now create *SecurityConfig.java* class, a configuration class to extends *WebSecurityConfigurerAdapter* class. 

```
package com.codeurinfo.easytransapi.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity // Enable Spring Security’s web security support
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) //To configure method-level security
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsServiceImpl customUserDetailsService;

  
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf()
      .disable()
      .authorizeRequests()
      .antMatchers("/api/auth/**").permitAll() // Grant access to every /api/auth based url
      .anyRequest().authenticated() // All other based url wil be allowed if authenticated
      .and()
      .sessionManagement()
      .sessionCreationPolicy(SessionCreationPolicy.STATELESS);//Force server not to never create an HttpSession
    
  }

  @Override
  @Bean
  public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }
}
``` 
You can learn more about the *SecurityConfig.java* class [here.](https://spring.io/guides/gs/securing-web/)

Once more class to code before we can test our API. For simplicity purpose, we'll be preloading users into the database and try to log in with their corresponding cridentials.

 Thanks to Spring boot's *CommandLineRunner* interface, we can create a preload class *DatabaseLoader.java* like this:


```
package com.codeurinfo.easytransapi;

import com.codeurinfo.easytransapi.security.model.ERole;
import com.codeurinfo.easytransapi.security.model.User;
import com.codeurinfo.easytransapi.security.repository.UserRepository;
import java.util.Arrays;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class DatabaseLoader implements CommandLineRunner {

  @Autowired
  UserRepository userRepository;

  @Autowired
  PasswordEncoder encoder;

  @Override
  public void run(String... args) throws Exception {
    // remember we use PasswordEncoder to configure the AuthenticationManagerBuilder in the SecurityConfig class
    // thus you must encode  pwd using the same encoder (BCryptPasswordEncoder) before persit
    String pwd1 = encoder.encode("will");
    String pwd2 = encoder.encode("user");
    userRepository.save(
      new User(
        "will",
        pwd1,
        "Wilson",
        Set.copyOf(Arrays.asList(ERole.ROLE_ADMIN, ERole.ROLE_USER))
      )
    );
    userRepository.save(
      new User(
        "user",
        pwd2,
        "Adjowa",
        Set.copyOf(Arrays.asList(ERole.ROLE_USER))
      )
    );
  }
}
``` 
Run the project, go to Postman and make a POST request to this endpoint :

```
http://localhost:8000/api/auth/login
```
You must have a result like this:

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1627061561428/Juik7Zlsk.png)

 Voila, through our REST API we can log in once and get a token to use in http request headers  for the next 10 hours. In the next tutorial, we'll see how to validate client request header token and how to grant access to endpoints according to users roles.

Hope you learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be up to date with new posts.















