Angular Spring Boot JWT Authentication example | Angular 6 + Spring Security + MySQL Full Stack – Part 2: Build Backend

spring-boot-angular-spring-security-jwt-authentication-feature-image

The tutorial is Part 2 of the series: Angular Spring Boot JWT Authentication example | Angular 6 + Spring Security + MySQL Full Stack. Today we’re gonna build a SpringBoot Security RestAPIs that can interact with MySQL database.

Part 1: Overview and Architecture.
Part 3: Build Angular Frontend

Related Posts:
Spring Boot + Angular 6 example | Spring Data JPA + REST + MySQL CRUD example

JWT Authentication with SpringBoot Security RestAPIs

Demo

Overview

Look back to the diagram for Spring Security/JWT classes that are separated into 3 layers:
– HTTP
– Spring Security
– REST API

spring-boot-angular-spring-security-jwt-authentication-architecture-diagram-back-end-server

For more details about this Architecture, please visit:
Spring Security – JWT Authentication Architecture | Spring Boot

Generate/Validate Token

We use a class named JwtProvider. It gets username from Authentication object, then builds JWT Token with username, Date() object, secretKey. JwtProvider can also be used to validate JWT Token:

class JwtProvider {
    @Value("${grokonez.app.jwtSecret}")
    private String jwtSecret;

    @Value("${grokonez.app.jwtExpiration}")
    private int jwtExpiration;

    public String generateJwtToken(Authentication authentication) {
        UserPrinciple userPrincipal = (UserPrinciple) authentication.getPrincipal();

        return Jwts.builder()
		                .setSubject((userPrincipal.getUsername()))
		                .setIssuedAt(new Date())
		                .setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
		                .signWith(SignatureAlgorithm.HS512, jwtSecret)
		                .compact();
    }
    
    public boolean validateJwtToken(String authToken) {
        Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
        return ...;
    }
    
    public String getUserNameFromJwtToken(String token) {
        return Jwts.parser()
			                .setSigningKey(jwtSecret)
			                .parseClaimsJws(token)
			                .getBody().getSubject();
    }
}
Filter the Request

We add our JwtAuthTokenFilter (that extends Spring OncePerRequestFilter abstract class) to the chain of filters.

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ...
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

JwtAuthTokenFilter validates the Token using JwtProvider:

class JwtAuthTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtProvider tokenProvider;

    @Override
    protected void doFilterInternal(...) {
        String jwt = getJwt(request);
        if (jwt!=null && tokenProvider.validateJwtToken(jwt)) {
            ...
        }
        filterChain.doFilter(request, response);
    }
}

Now we have 2 cases:
– Login/SignUp: RestAPI with non-protected APIs -> authenticate Login Request with AuthenticationManager, if error occurs, handle AuthenticationException with AuthenticationEntryPoint.
– With protected Resources:
+ jwt token is null/invalid -> if Authenticated Error occurs, handle AuthenticationException with AuthenticationEntryPoint.
+ jwt token is valid -> from token, get User information, then create AuthenticationToken.

Create AuthenticationToken from Token

JwtAuthTokenFilter extracts username/password from the received token using JwtProvider, then based on the extracted data, JwtAuthTokenFilter:
– creates a AuthenticationToken (that implements Authentication)
– uses the AuthenticationToken as Authentication object and stores it in the SecurityContext for future filter uses (e.g: Authorization filters).

In this tutorial, we use UsernamePasswordAuthenticationToken:

// extract user information
String username = tokenProvider.getUserNameFromJwtToken(jwt);
UserDetails userDetails = userDetailsService.loadUserByUsername(username);

// create AuthenticationToken
UsernamePasswordAuthenticationToken authentication
        = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
Store Authentication object in SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);

SecurityContextHolder is the most fundamental object where we store details of the present security context of the application (includes details of the principal). Spring Security uses an Authentication object to represent this information and we can query this Authentication object from anywhere in our application:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// currently authenticated user
Object principal = authentication.getPrincipal();

getContext() returns an instance of SecurityContext interface that holds the Authentication and possibly request-specific security information.

Authenticate with AuthenticationProvider

These are some authentication providers that Spring Framework provides, in this example, we use DaoAuthenticationProvider. This Provider works well with form-based logins or HTTP Basic authentication which submits a simple username/password authentication request.
It authenticates the User simply by comparing the password submitted in a UsernamePasswordAuthenticationToken against the one loaded by the UserDetailsService (as a DAO):

@Autowired
AuthenticationManager authenticationManager;
...
Authentication authentication = 
				authenticationManager.authenticate(
				    new UsernamePasswordAuthenticationToken(loginRequest.username, loginRequest.password)
				);

Configuring this provider is simple with AuthenticationManagerBuilder:

class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

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

For more details about AuthenticationManager & AuthenticationProvider, please visit:
Delegate AuthenticationToken for AuthenticationManagager.

Retrieve User details with UserDetailsService

We can obtain a principal from the Authentication object. This principal can be cast into a UserDetails object to lookup the username, password and GrantedAuthoritys.

Therefore, after authenticating is successful, we can simply get UserDetails from Authentication object:

UserDetails userDetails = (UserDetails) authentication.getPrincipal();
// userDetails.getUsername()
// userDetails.getPassword()
// userDetails.getAuthorities()

DaoAuthenticationProvider also uses UserDetailsService for getting UserDetails object. This is the common approach in which we only pass a String-based ‘username’ argument and returns a UserDetails:

public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

It is simple to implement UserDetailsService and easy for us to retrieve authentication information using a persistence strategy:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    	User user = userRepository.findByUsername(username).orElseThrow(
    			() -> new UsernameNotFoundException("User Not Found with -> username or email : " + username));

    	return UserPrinciple.build(user); // UserPrinciple implements UserDetails
    }
}
Protect Resources with HTTPSecurity & Method Security Expressions
Configure HTTPSecurity

To help Spring Security know when we want to require all users to be authenticated, which Exception Handler to be chosen, which filter and when we want it to work. We implement WebSecurityConfigurerAdapter and provide a configuration in the configure(HttpSecurity http) method:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().
                authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                ...;
        
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
Method Security Expressions

Spring Security provides some annotations for pre and post-invocation authorization checks, filtering of submitted collection arguments or return values: @PreAuthorize, @PreFilter, @PostAuthorize and @PostFilter.

To enable Method Security Expressions, we use @EnableGlobalMethodSecurity annotation:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    ...
}

In the code below, we use the most useful annotation @PreAuthorize to decide whether a method can actually be invoked or not:

@RestController
public class TestRestAPIs {
	
    @GetMapping("/api/test/user")
    @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
    public String userAccess() {
    	return ">>> User Contents!";
    }

    @GetMapping("/api/test/pm")
    @PreAuthorize("hasRole('PM') or hasRole('ADMIN')")
    public String projectManagementAccess() {
    	return ">>> Project Management Board";
    }
	
    @GetMapping("/api/test/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public String adminAccess() {
        return ">>> Admin Contents";
    }
}
Handle AuthenticationException – AuthenticationEntryPoint

If the user requests a secure HTTP resource without being authenticated, AuthenticationEntryPoint will be called. At this time, an AuthenticationException is thrown, commence() method on the entry point is triggered:

@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {
   
    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e) 
                            throws IOException, ServletException {
    	
        logger.error("Unauthorized error. Message - {}", e.getMessage());
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error -> Unauthorized");
    }
}

Spring Boot server for JWT Authentication Overview

Goal

The diagram below show how our system handles User Registration and User Login processes:

angular-spring-security-jwt-authentication-work-process-diagram

– We expose 2 RestAPIs to signup and signin:

  • /api/auth/signup -> sign up

    spring-boot-angular-spring-security-jwt-authentication-back-end-spring-signup-request

  • /api/auth/signin -> sign in

    spring-boot-angular-spring-security-jwt-authentication-back-end-spring-signin-request

– We expose 3 RestAPIs to test protected resources:

@GetMapping("/api/test/user")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public String userAccess() {
	return ">>> User Contents!";
}

@GetMapping("/api/test/pm")
@PreAuthorize("hasRole('PM') or hasRole('ADMIN')")
public String projectManagementAccess() {
	return ">>> Board Management Project";
}

@GetMapping("/api/test/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminAccess() {
	return ">>> Admin Contents";
}
  • Access Successfully ->

    spring-boot-angular-spring-security-jwt-authentication-back-end-spring-access-user-role-request

  • Unauthorized ->

    spring-boot-angular-spring-security-jwt-authentication-back-end-spring-access-request-unauthorized

Technologies

– Spring Boot 2
– jjwt – 0.9.0
– Spring Security
– Spring JPA
– MySQL

Project Structure

spring-boot-angular-spring-security-jwt-authentication-back-end-spring-project-structure

model package defines 2 entities User & Role that have many-to-many relationship:

spring-security-jwt-json-web-token-authentication-springboot-spring-jpa-postgresql-uml-modeling

repository package contains interfaces that use Hibernate JPA to store/retrieve data from MySQL database.
controller package defines RestAPIs for user signup/signin and testing protected resources that is secured with JWT.
message package defines payload data transferred from user agents (Browser/RestClient…) to RestAPIs and message back.
security package is the main part of the project that implements JWT security.

Practice

Create SpringBoot project

Dependency for the Project:


	org.springframework.boot
	spring-boot-starter-data-jpa



	org.springframework.boot
	spring-boot-starter-security



	org.springframework.boot
	spring-boot-starter-web



	mysql
	mysql-connector-java
	runtime




	io.jsonwebtoken
	jjwt
	0.9.0

Create Models

User model includes 5 attributes:

  • id
  • name
  • username
  • email
  • password

model/User.java

package com.grokonez.jwtauthentication.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

import org.hibernate.annotations.NaturalId;

@Entity
@Table(name = "users", uniqueConstraints = {
        @UniqueConstraint(columnNames = {
            "username"
        }),
        @UniqueConstraint(columnNames = {
            "email"
        })
})
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    @Size(min=3, max = 50)
    private String name;

    @NotBlank
    @Size(min=3, max = 50)
    private String username;

    @NaturalId
    @NotBlank
    @Size(max = 50)
    @Email
    private String email;

    @NotBlank
    @Size(min=6, max = 100)
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles", 
    	joinColumns = @JoinColumn(name = "user_id"), 
    	inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set roles = new HashSet<>();

    public User() {}

    public User(String name, String username, String email, String password) {
        this.name = name;
        this.username = username;
        this.email = email;
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set getRoles() {
        return roles;
    }

    public void setRoles(Set roles) {
        this.roles = roles;
    }
}

Role model with 2 attributes:

  • id
  • rolename

model/Role.java

package com.grokonez.jwtauthentication.model;

import javax.persistence.Column;
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;

import org.hibernate.annotations.NaturalId;

@Entity
@Table(name = "roles")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    @NaturalId
    @Column(length = 60)
    private RoleName name;

    public Role() {}

    public Role(RoleName name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public RoleName getName() {
        return name;
    }

    public void setName(RoleName name) {
        this.name = name;
    }
}

model/RoleName.java

package com.grokonez.jwtauthentication.model;

public enum  RoleName {
    ROLE_USER,
    ROLE_PM,
    ROLE_ADMIN
}
Implement Repository

repository/UserRepository.java

package com.grokonez.jwtauthentication.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.grokonez.jwtauthentication.model.User;

@Repository
public interface UserRepository extends JpaRepository {
    Optional findByUsername(String username);
    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

repository/UserRepository.java

package com.grokonez.jwtauthentication.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.grokonez.jwtauthentication.model.Role;
import com.grokonez.jwtauthentication.model.RoleName;

@Repository
public interface RoleRepository extends JpaRepository {
    Optional findByName(RoleName roleName);
}

For more details about Spring JPA with MySQL, please visit:
How to use Spring JPA MySQL | Spring Boot

Implement JWT Security

security/WebSecurityConfig.java

package com.grokonez.jwtauthentication.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

import com.grokonez.jwtauthentication.security.jwt.JwtAuthEntryPoint;
import com.grokonez.jwtauthentication.security.jwt.JwtAuthTokenFilter;
import com.grokonez.jwtauthentication.security.services.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
		prePostEnabled = true
)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Autowired
    private JwtAuthEntryPoint unauthorizedHandler;

    @Bean
    public JwtAuthTokenFilter authenticationJwtTokenFilter() {
        return new JwtAuthTokenFilter();
    }

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

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

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().
                authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
Create UserDetails Service

UserDetailsServiceImpl implements UserDetailsService and overrides loadUserByUsername() method.

loadUserByUsername method finds a record from users database tables to build a UserDetails object for authentication.

security/services/UserDetailsServiceImpl.java

package com.grokonez.jwtauthentication.security.services;

import com.grokonez.jwtauthentication.model.User;
import com.grokonez.jwtauthentication.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  UserRepository userRepository;

  @Override
  @Transactional
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

    User user = userRepository.findByUsername(username).orElseThrow(
        () -> new UsernameNotFoundException("User Not Found with -> username or email : " + username));

    return UserPrinciple.build(user);
  }
}

UserPrinciple will implement UserDetails.
UserPrinciple is not used directly by Spring Security for security purposes.
It simply stores user information which is later encapsulated into Authentication objects. This allows non-security related user information (such as email addresses, telephone numbers etc) to be stored.

security/services/UserPrinciple.java

package com.grokonez.jwtauthentication.security.services;

import com.grokonez.jwtauthentication.model.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class UserPrinciple implements UserDetails {
	private static final long serialVersionUID = 1L;

	private Long id;

    private String name;

    private String username;

    private String email;

    @JsonIgnore
    private String password;

    private Collection authorities;

    public UserPrinciple(Long id, String name, 
			    		String username, String email, String password, 
			    		Collection authorities) {
        this.id = id;
        this.name = name;
        this.username = username;
        this.email = email;
        this.password = password;
        this.authorities = authorities;
    }

    public static UserPrinciple build(User user) {
        List authorities = user.getRoles().stream().map(role ->
                new SimpleGrantedAuthority(role.getName().name())
        ).collect(Collectors.toList());

        return new UserPrinciple(
                user.getId(),
                user.getName(),
                user.getUsername(),
                user.getEmail(),
                user.getPassword(),
                authorities
        );
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

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

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

    @Override
    public Collection getAuthorities() {
        return authorities;
    }

    @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;
        
        UserPrinciple user = (UserPrinciple) o;
        return Objects.equals(id, user.id);
    }
}
JWT Authentication Classes

JwtAuthTokenFilter extends OncePerRequestFilter.

org.springframework.web.filter.OncePerRequestFilter
-> Executes once per request. This is a filter base class that is used to guarantee a single execution per request dispatch. It provides a doFilterInternal method with HttpServletRequest and HttpServletResponse arguments.

Inside JwtAuthTokenFilter class, the doFilterInternal method will:

  • get JWT token from header
  • validate JWT
  • parse username from validated JWT
  • load data from users table, then build an authentication object
  • set the authentication object to Security Context

security/jwt/JwtAuthTokenFilter.java

package com.grokonez.jwtauthentication.security.jwt;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.OncePerRequestFilter;

import com.grokonez.jwtauthentication.security.services.UserDetailsServiceImpl;

public class JwtAuthTokenFilter extends OncePerRequestFilter {

  @Autowired
  private JwtProvider tokenProvider;

  @Autowired
  private UserDetailsServiceImpl userDetailsService;

  private static final Logger logger = LoggerFactory.getLogger(JwtAuthTokenFilter.class);

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {
    try {

      String jwt = getJwt(request);
      if (jwt != null && tokenProvider.validateJwtToken(jwt)) {
        String username = tokenProvider.getUserNameFromJwtToken(jwt);

        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
            userDetails, null, userDetails.getAuthorities());
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

        SecurityContextHolder.getContext().setAuthentication(authentication);
      }
    } catch (Exception e) {
      logger.error("Can NOT set user authentication -> Message: {}", e);
    }

    filterChain.doFilter(request, response);
  }

  private String getJwt(HttpServletRequest request) {
    String authHeader = request.getHeader("Authorization");

    if (authHeader != null && authHeader.startsWith("Bearer ")) {
      return authHeader.replace("Bearer ", "");
    }

    return null;
  }
}

JwtAuthEntryPoint is used to handle Error exception when having unauthorized requests.

security/jwt/JwtAuthEntryPoint.java

package com.grokonez.jwtauthentication.security.jwt;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthEntryPoint.class);
    
    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e) 
                        		 throws IOException, ServletException {
    	
        logger.error("Unauthorized error. Message - {}", e.getMessage());
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error -> Unauthorized");
    }
}

JwtProvider is an util class -> it implements useful functions:

  • generate a JWT token
  • valiate a JWT token
  • parse username from JWT token

security/jwt/JwtProvider.java

package com.grokonez.jwtauthentication.security.jwt;

import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import com.grokonez.jwtauthentication.security.services.UserPrinciple;

import java.util.Date;

@Component
public class JwtProvider {

    private static final Logger logger = LoggerFactory.getLogger(JwtProvider.class);

    @Value("${grokonez.app.jwtSecret}")
    private String jwtSecret;

    @Value("${grokonez.app.jwtExpiration}")
    private int jwtExpiration;

    public String generateJwtToken(Authentication authentication) {

        UserPrinciple userPrincipal = (UserPrinciple) authentication.getPrincipal();

        return Jwts.builder()
		                .setSubject((userPrincipal.getUsername()))
		                .setIssuedAt(new Date())
		                .setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
		                .signWith(SignatureAlgorithm.HS512, jwtSecret)
		                .compact();
    }
    
    public boolean validateJwtToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException e) {
            logger.error("Invalid JWT signature -> Message: {} ", e);
        } catch (MalformedJwtException e) {
            logger.error("Invalid JWT token -> Message: {}", e);
        } catch (ExpiredJwtException e) {
            logger.error("Expired JWT token -> Message: {}", e);
        } catch (UnsupportedJwtException e) {
            logger.error("Unsupported JWT token -> Message: {}", e);
        } catch (IllegalArgumentException e) {
            logger.error("JWT claims string is empty -> Message: {}", e);
        }
        
        return false;
    }
    
    public String getUserNameFromJwtToken(String token) {
        return Jwts.parser()
			                .setSigningKey(jwtSecret)
			                .parseClaimsJws(token)
			                .getBody().getSubject();
    }
}
Implement RestControllers
Create Payload Message

LoginForm with username & password.

message/request/LoginForm.java

package com.grokonez.jwtauthentication.message.request;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class LoginForm {
    @NotBlank
    @Size(min=3, max = 60)
    private String username;

    @NotBlank
    @Size(min = 6, max = 40)
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

SignUpForm includes:

  • name
  • username
  • email
  • role
  • password

message/request/SignUpForm.java

package com.grokonez.jwtauthentication.message.request;

import java.util.Set;

import javax.validation.constraints.*;

public class SignUpForm {
    @NotBlank
    @Size(min = 3, max = 50)
    private String name;

    @NotBlank
    @Size(min = 3, max = 50)
    private String username;

    @NotBlank
    @Size(max = 60)
    @Email
    private String email;
    
    private Set role;
    
    @NotBlank
    @Size(min = 6, max = 40)
    private String password;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    
    public Set getRole() {
    	return this.role;
    }
    
    public void setRole(Set role) {
    	this.role = role;
    }
}

JwtResponse object will be returned by SpringBoot server once an authentication is successful, it contains:

  • JWT Token
  • Schema Type of Token
  • Username
  • Array of User’s Authorities

message/response/JwtResponse.java

package com.grokonez.jwtauthentication.message.response;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;

public class JwtResponse {
  private String token;
  private String type = "Bearer";
  private String username;
  private Collection authorities;

  public JwtResponse(String accessToken, String username, Collection authorities) {
    this.token = accessToken;
    this.username = username;
    this.authorities = authorities;
  }

  public String getAccessToken() {
    return token;
  }

  public void setAccessToken(String accessToken) {
    this.token = accessToken;
  }

  public String getTokenType() {
    return type;
  }

  public void setTokenType(String tokenType) {
    this.type = tokenType;
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }
  
  public Collection getAuthorities() {
    return authorities;
  }
}

ResponseMessage object is just a message object.

message/response/ResponseMessage.java

package com.grokonez.jwtauthentication.message.response;

public class ResponseMessage {
  private String message;

  public ResponseMessage(String message) {
    this.message = message;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }
}
RestAPIs Controller

AuthRestAPIs defines 2 APIs:

  • /api/auth/signup: sign up
    -> check username/email is already in use.
    -> create User object
    -> store to database
  • /api/auth/signin: sign in
    -> attempt to authenticate with AuthenticationManager bean.
    -> add authentication object to SecurityContextHolder
    -> Generate JWT token, then return JWT to client

controller/AuthRestAPIs.java

package com.grokonez.jwtauthentication.controller;

import java.util.HashSet;
import java.util.Set;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.grokonez.jwtauthentication.message.request.LoginForm;
import com.grokonez.jwtauthentication.message.request.SignUpForm;
import com.grokonez.jwtauthentication.message.response.JwtResponse;
import com.grokonez.jwtauthentication.message.response.ResponseMessage;
import com.grokonez.jwtauthentication.model.Role;
import com.grokonez.jwtauthentication.model.RoleName;
import com.grokonez.jwtauthentication.model.User;
import com.grokonez.jwtauthentication.repository.RoleRepository;
import com.grokonez.jwtauthentication.repository.UserRepository;
import com.grokonez.jwtauthentication.security.jwt.JwtProvider;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class AuthRestAPIs {

  @Autowired
  AuthenticationManager authenticationManager;

  @Autowired
  UserRepository userRepository;

  @Autowired
  RoleRepository roleRepository;

  @Autowired
  PasswordEncoder encoder;

  @Autowired
  JwtProvider jwtProvider;

  @PostMapping("/signin")
  public ResponseEntity authenticateUser(@Valid @RequestBody LoginForm loginRequest) {

    Authentication authentication = authenticationManager.authenticate(
        new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));

    SecurityContextHolder.getContext().setAuthentication(authentication);

    String jwt = jwtProvider.generateJwtToken(authentication);
    UserDetails userDetails = (UserDetails) authentication.getPrincipal();

    return ResponseEntity.ok(new JwtResponse(jwt, userDetails.getUsername(), userDetails.getAuthorities()));
  }

  @PostMapping("/signup")
  public ResponseEntity registerUser(@Valid @RequestBody SignUpForm signUpRequest) {
    if (userRepository.existsByUsername(signUpRequest.getUsername())) {
      return new ResponseEntity<>(new ResponseMessage("Fail -> Username is already taken!"),
          HttpStatus.BAD_REQUEST);
    }

    if (userRepository.existsByEmail(signUpRequest.getEmail())) {
      return new ResponseEntity<>(new ResponseMessage("Fail -> Email is already in use!"),
          HttpStatus.BAD_REQUEST);
    }

    // Creating user's account
    User user = new User(signUpRequest.getName(), signUpRequest.getUsername(), signUpRequest.getEmail(),
        encoder.encode(signUpRequest.getPassword()));

    Set strRoles = signUpRequest.getRole();
    Set roles = new HashSet<>();

    strRoles.forEach(role -> {
      switch (role) {
      case "admin":
        Role adminRole = roleRepository.findByName(RoleName.ROLE_ADMIN)
            .orElseThrow(() -> new RuntimeException("Fail! -> Cause: User Role not find."));
        roles.add(adminRole);

        break;
      case "pm":
        Role pmRole = roleRepository.findByName(RoleName.ROLE_PM)
            .orElseThrow(() -> new RuntimeException("Fail! -> Cause: User Role not find."));
        roles.add(pmRole);

        break;
      default:
        Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
            .orElseThrow(() -> new RuntimeException("Fail! -> Cause: User Role not find."));
        roles.add(userRole);
      }
    });

    user.setRoles(roles);
    userRepository.save(user);

    return new ResponseEntity<>(new ResponseMessage("User registered successfully!"), HttpStatus.OK);
  }
}

TestRestAPIs define 3 RestAPIs:

  • /api/test/user -> access by users has USER_ROLE or ADMIN_ROLE
  • /api/test/pm -> access by users has USER_PM or ADMIN_ROLE
  • /api/test/admin -> access by users has ADMIN_ROLE

controller/TestRestAPIs.java

package com.grokonez.jwtauthentication.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
public class TestRestAPIs {
  
  @GetMapping("/api/test/user")
  @PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
  public String userAccess() {
    return ">>> User Contents!";
  }

  @GetMapping("/api/test/pm")
  @PreAuthorize("hasRole('PM') or hasRole('ADMIN')")
  public String projectManagementAccess() {
    return ">>> Project Management Board";
  }
  
  @GetMapping("/api/test/admin")
  @PreAuthorize("hasRole('ADMIN')")
  public String adminAccess() {
    return ">>> Admin Contents";
  }
}
Configure Spring Datasource, JPA and define App Properties

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.generate-ddl=true

# App Properties
grokonez.app.jwtSecret=jwtGrokonezSecretKey
grokonez.app.jwtExpiration=86400
Run & Check Results
Start SpringBoot

– Start Springboot server by commandline mvn spring-boot:run

– Check database tables ->

spring-boot-angular-spring-security-jwt-authentication-back-end-mysql-tables-schema

– Insert data to roles table ->

INSERT INTO roles(name) VALUES('ROLE_USER');
INSERT INTO roles(name) VALUES('ROLE_PM');
INSERT INTO roles(name) VALUES('ROLE_ADMIN');
SignUp

Sign-Up 3 users:

  • Jack has ROLE_USER role
  • Adam has ROLE_PM & ROLE_USER roles
  • Thomas has ROLE_ADMIN role

spring-boot-angular-spring-security-jwt-authentication-back-end-sign-up

– Check database’s tables ->

spring-boot-angular-spring-security-jwt-authentication-back-end-sign-up-database

SignIn and Access Protected Resources

Jack can access api/test/user url, can NOT access others.

-> Sign In:

spring-boot-angular-spring-security-jwt-authentication-back-end-sign-in-user

-> Access Protected Resources:

spring-boot-angular-spring-security-jwt-authentication-back-end-access-user-api-success-with-user-role

spring-boot-angular-spring-security-jwt-authentication-back-end-access-pm-role-fail-with-user-role

Thomas can access all URLs.

-> Sign In:

spring-boot-angular-spring-security-jwt-authentication-back-end-sign-in-admin

-> Access Protected Resources:

spring-boot-angular-spring-security-jwt-authentication-back-end-access-user-api-success-with-admin-role

spring-boot-angular-spring-security-jwt-authentication-back-end-access-pm-api-success-with-admin-role

spring-boot-angular-spring-security-jwt-authentication-back-end-access-admin-api-success-with-admin-role

Adam can access api/test/user and api/test/pm url.
Can NOT access /api/test/admin url.

SourceCode

SpringBootJwtAuthentication



By grokonez | October 26, 2018.

Last updated on February 7, 2020.



Related Posts


63 thoughts on “Angular Spring Boot JWT Authentication example | Angular 6 + Spring Security + MySQL Full Stack – Part 2: Build Backend”

    1. Not sure if it is, but I am very happy with Postman. It was a web browser (chrome) plugin but is now available as a standalone program.

  1. Thanks for this great tutorial. It was really helpful and everything works fine from postman. One thing however is that after running the application when I access localhost:8080, no authentication form is show and I cannot login from the browser. I tried adding httpBasic for it so that configure method now looks like the following:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	http.cors().and().csrf().disable().authorizeRequests().antMatchers("/api/auth/**").permitAll().anyRequest()
    			.authenticated().and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
    			.httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    
    	http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
    

    But the basic login form is still not visible. Could you please let me know how the basic login form can be shown so that I could login from the browser?

    1. Run Angular and try to access from there it might run.
      You need to follow the complete tutorial series of this article.

  2. Thank you for this powerful tutorial which works from the first run. I created this auth application with the resource of registered users. How to implement authorization with this app token on another restful api application out of the context of this app.

  3. Hi,

    First of all, thank you for this amazing tutorial. Secondly, I have one question regarding the custom JwtAuthTokenFilter. In the doFilterInternal() method we validate the JwtToken and if its valid, we get the username from the token. So far so good. However, after getting the username from the token, a call to the userDetailsService is made (loadUserByUsername). This is the actual call to the database. What I do not understand is that when the user has a token already, which is valid, there is still a call made to the database. I would expect that if the token is valid, we would not make another call to the database.

    Currently to me this seem to be the situation:
    User tries to log in -> go through all Spring filters as well as through JwtAuthTokenFilter -> No JwtToken present thus no validation is done -> into controller endpoint -> call authenticationManager.authentication (meaning we make a call to the database) -> verify user and generate JwtToken.

    Then when a user tries to access a protected resource -> go through all Spring filters -> JwtAuthTokenFilter -> JwtToken present thus we validate it -> if valid: userDetailsService.loadUserByUsername() -> call database to verify user -> …

    However, it would make more sense to me that if the JwtToken is present, the user is validated. What am I understand wrong?

    Regards,

    Bart

  4. I am confused with one thing, when I try to sign in for the first time ever using postman, I am sending base 64 of the jwttoken stored in application.properties
    and I get MalformedJwtException what am I missing?

  5. Error:(25, 16) java: constructor JwtAuthTokenFilter in class org.pro.security.JWT.JwtAuthTokenFilter cannot be applied to given types;
    required: org.pro.security.JWT.JwtProvider,org.pro.security.service.UserDetailsServiceImpl
    found: no arguments
    reason: actual and formal argument lists differ in length

  6. public String generateJwtToken(Authentication authentication) {
    
            UserPrinciple userPrincipal = (UserPrinciple) authentication.getPrincipal();
    
            return Jwts.builder()
    		                .setSubject((userPrincipal.getUsername()))
    		                .setIssuedAt(new Date())
    		                .setExpiration(new Date((new Date()).getTime() + jwtExpiration*1000))
    		                .signWith(SignatureAlgorithm.HS512, jwtSecret)
    		                .compact();
        }
    

    it is show error Jwts con not be resolve. can any help me how solve this error.

  7. Hello I get this error message if I try to sign in.

    {
        "timestamp": "2019-02-12T17:57:17.195+0000",
        "status": 500,
        "error": "Internal Server Error",
        "message": "javax/xml/bind/DatatypeConverter",
        "path": "/api/auth/signin"
    }
    

    I think it has something to do with this method:

            String jwt = jwtProvider.generateJwtToken(authentication);
    

    in the AuthRestApi.
    To you have any idea how to solve this?

  8. Really impressed with this tutorial.Very informative.I setup both angular and spring boot in my desktop and tried to run the application.I have got one issue.The login attempt is failed with unknown issue.I am getting “Access to XMLHttpRequest at ‘http://localhost:8080/api/auth/signin’ from origin ‘http://localhost:4200′ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status”.in the developer tool.In the server console,i can see some entries like ”
    2019-02-18 20:44:20.557 DEBUG 8088 — [nio-8080-exec-8] o.s.s.w.util.matcher.AndRequestMatcher : Trying to match using Ant [pattern=’/**’, GET]
    2019-02-18 20:44:20.558 DEBUG 8088 — [nio-8080-exec-8] o.s.s.w.u.matcher.AntPathRequestMatcher : Request ‘OPTIONS /auth/signin’ doesn’t match ‘GET /**”
    Can anybody help me? Thanks in advance

  9. Adding to the previous comment:
    Signup is also failed with same error.

    signup:1 Access to XMLHttpRequest at ‘http://localhost:8080/api/auth/signup’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

  10. {“timestamp”:1551923158440,”status”:401,”error”:”Unauthorized”,”message”:”Full authentication is required to access this resource”,”path”:”/myproject/api/auth/signup”}

    Why?

  11. Dont work °_° why? ç_ç

    2019-03-07 06:07:38.694 INFO 48424 — [ost-startStop-1] org.hibernate.Version : HHH000412: Hibernate Core {5.0.11.Final}
    2019-03-07 06:07:38.697 INFO 48424 — [ost-startStop-1] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
    2019-03-07 06:07:38.699 INFO 48424 — [ost-startStop-1] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
    2019-03-07 06:07:38.825 INFO 48424 — [ost-startStop-1] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
    2019-03-07 06:07:38.969 INFO 48424 — [ost-startStop-1] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
    2019-03-07 06:07:39.218 ERROR 48424 — [ost-startStop-1] o.s.b.c.embedded.tomcat.TomcatStarter : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name ‘jwtAuthTokenFilter’: Unsatisfied dependency expressed through field ‘userDetailsService’; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userDetailsServiceImpl’: Unsatisfied dependency expressed through field ‘userRepository’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘userRepository’: Cannot create inner bean ‘(inner bean)#2daaa964’ of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property ‘entityManager’; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘(inner bean)#2daaa964’: Cannot resolve reference to bean ‘entityManagerFactory’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘entityManagerFactory’ defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: myapp.project.web.entities.User.roles[myapp.project.web.entities.Role]
    2019-03-07 06:07:39.249 WARN 48424 — [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization – cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    2019-03-07 06:07:39.269 ERROR 48424 — [ main] o.s.boot.SpringApplication : Application startup failed

    org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:137) ~[spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:536) ~[spring-context-4.3.4.RELEASE.jar:4.3.4.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:761) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:371) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1186) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1175) [spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]
    at myapp.project.SpringBootJwtAuthenticationApplication.main(SpringBootJwtAuthenticationApplication.java:10) [classes/:na]
    Caused by: org.springframework.boot.context.embedded.EmbeddedServletContainerException: Unable to start embedded Tomcat
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:115) ~[spring-boot-1.4.2.RELEASE.jar:1.4.2.RELEASE]

  12. Great guide! Do you happen to know why

    public class JwtAuthTokenFilter extends OncePerRequestFilter {
        @Autowired
        private JwtProvider tokenProvider;
    
        @Autowired
        private UserDetailsServiceImpl userDetailsService;
    }
    

    comes out as ‘Could not autowire. No beans found for ‘…’ type found. It’s happening to both of them and also for

    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Autowired
        UserDetailsServiceImpl userDetailsService;
    
        @Autowired
        private JwtAuthEntryPoint unauthorizedHandler;
    }
    

    And

    public class AuthRestAPIs {
    @Autowired
        JwtProvider jwtProvider;
    }
    

    I’m not entirely sure why it’s errored out

  13. Hi, thanks for tutorial, it seems I have issue when register
    “Access to XMLHttpRequest at ‘http://localhost:8080/api/auth/signin’ from origin ‘http://localhost:4200’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”. This code i get from the link you provided. Then I try using Postman also not working.

  14. Why i cant signUp ? error respone :

    Unauthorized error. Message – Full authentication is required to access this resource

  15. Hi, I would like to enhance this solution for “remember me” functionality. Do You have any good example how to do this. I’m trying for few days, but without any good results. Thank you in advice.

  16. When trying to access /api/test/user, I receive the following:

    c.s.m.security.jwt.JwtAuthEntryPoint : Unauthorized error. Message – Full authentication is required to access this resource

    I debugged and in this method JwtAuthTokenFilter.getJwt

    private String getJwt(HttpServletRequest request) {
    String authHeader = request.getHeader(“Authorization”);

    authHeader is null. Why don’t I receive the authentication headers, even though I passed it as advised with ‘Bearer ‘ + token.

    Can anybody please help me?

    1. Hello,

      It didn’t work because I was communicating through zuul with the microservice and I had to pass

      # Pass Authorization header downstream
      sensitiveHeaders: Cookie,Set-Cookie

      in the zuul cnofiguration in order to pass the authorization header further to the microservice.

  17. 2019-05-25 18:11:42.483 INFO 14608 — [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.9.Final}
    2019-05-25 18:11:42.485 INFO 14608 — [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
    2019-05-25 18:11:42.647 INFO 14608 — [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
    2019-05-25 18:11:42.839 INFO 14608 — [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
    2019-05-25 18:11:43.142 INFO 14608 — [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit ‘default’
    2019-05-25 18:11:43.435 INFO 14608 — [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService ‘applicationTaskExecutor’
    2019-05-25 18:11:43.519 WARN 14608 — [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
    2019-05-25 18:11:43.903 INFO 14608 — [ main] .s.s.UserDetailsServiceAutoConfiguration :

    Using generated security password: 52c2b7fe-cb84-42e1-882e-10c57c2410aa

    2019-05-25 18:11:44.039 INFO 14608 — [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@4e140497, org.springframework.security.web.context.SecurityContextPersistenceFilter@7fdd43cd, org.springframework.security.web.header.HeaderWriterFilter@3cc053, org.springframework.security.web.csrf.CsrfFilter@39b626e5, org.springframework.security.web.authentication.logout.LogoutFilter@4792f119, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@27585351, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@6f9ab79d, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@481b2f10, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@56826a75, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@2ce03e86, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4877919f, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@2b6c7012, org.springframework.security.web.session.SessionManagementFilter@7fbd3e75, org.springframework.security.web.access.ExceptionTranslationFilter@1a1ccaaf, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@477021ee]
    2019-05-25 18:11:44.172 INFO 14608 — [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8082 (http) with context path ”
    2019-05-25 18:11:44.176 INFO 14608 — [ main] c.w.j.S.SpringbootApplication : Started SpringbootApplication in 4.916 seconds (JVM running for 5.339)
    2019-05-25 18:12:49.348 INFO 14608 — [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet ‘dispatcherServlet’
    2019-05-25 18:12:49.348 INFO 14608 — [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet ‘dispatcherServlet’
    2019-05-25 18:12:49.357 INFO 14608 — [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 9 ms

    ===================================
    spring.datasource.url=jdbc:mysql://localhost:3306/mydb1?useSSL=false
    spring.datasource.username=root
    spring.datasource.password=password
    spring.jpa.generate-ddl=true

    # App Properties
    grokonez.app.jwtSecret=jwtGrokonezSecretKey
    grokonez.app.jwtExpiration=86400

    ====================================

    could not hit database and not created table also please guide me

  18. Unauthorized error. Message – Full authentication is required to access this resource

    How do i reslove it ?

  19. If I had logged in thomasgkz in one tab and while i try to log same thomasgkz in another tab it dowsnt show unauthorized it was generating token again

  20. config Cors

    @Bean
    	CorsConfigurationSource corsConfigurationSource() {
    		final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    		source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
    		return source;
    	}
    
  21. Thanks for the detailed explanation. Could you please let me know why I am getting 404 Not found error?

    Spring boot application and DB is up and running. I don’t see any error in console. However, I am getting 404 Not found error in Postman

    1. I found the solution..I did everything excepts copying the correct dependencies. Now I copied the correct dependencies and it’s working. Thanks a lot Sir for this great tutorial !!!

  22. Could you please help me , how to solve this issue
    getting the below error
    java.lang.RuntimeException: Fail! -> Cause: User Role not find.
    at com.grokonez.jwtauthentication.controller.AuthRestAPIs.lambda$3(AuthRestAPIs.java:103)

  23. So, this worked perfectly me.

    But now i can’t access my backend service via browser xD
    What i mean is, that by going to localhost:8082/someTable i get the following error:

    “There was an unexpected error (type=Unauthorized, status=401).
    Error -> Unauthorized”

    anyway to counter this?
    Thx in advance

Got Something To Say:

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

*