This tutorial helps you build a Spring Boot Authentication (Login & Registration) & role-based Authorization example with JWT, Spring Security and Spring Data MongoDB. You’ll know:
- Appropriate Flow for User Signup & User Login with JWT Authentication
- Spring Boot Application Architecture with Spring Security
- How to configure Spring Security to work with JWT
- How to define Data Models and association for Authentication and Authorization
- Way to use Spring Data MongoDB to interact with MongoDB Database
More Practice:
– Spring Boot JWT Authentication with Spring Security, Spring JPA
– Spring Boot + GraphQL + MongoDB example
– Spring Boot with MongoDB CRUD example using Spring Data
– Spring Boot Unit Test for Rest Controller
– @RestControllerAdvice example in Spring Boot
– Spring Boot, MongoDB, Reactive CRUD example
– Documentation: Spring Boot Swagger 3 example
– Caching: Spring Boot Redis Cache example
– Spring Boot custom Validation example
– Dockerize: Docker Compose: MongoDB and Spring Boot example
Contents
- Spring Boot JWT Authentication with MongoDB example
- Spring Boot Signup & Login with JWT Authentication Flow
- Spring Boot Server Architecture with Spring Security
- Technology
- Project Structure
- Setup new Spring Boot project
- Configure Spring Data MongoDB & App properties
- Create the models
- Implement Repositories
- Configure Spring Security
- Implement UserDetails & UserDetailsService
- Filter the Requests
- Create JWT Utility class
- Handle Authentication Exception
- Define payloads for Spring RestController
- Create Spring RestAPIs Controllers
- Run & Test
- Solve Problem: javax.validation cannot be resolved
- Problem with newer JDK
- Conclusion
- Further Reading
- Source Code
Spring Boot JWT Authentication with MongoDB example
Let’s me describe our Spring Boot application.
- User can signup new account, or login with username & password.
- By User’s role (admin, moderator, user), we authorize the User to access resources (role-based Authorization)
So we’re gonna provide APIs as following table:
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 |
– Spring Security will manage cors, csrf, session, rules for protected resources, authentication & authorization along with exception handler.
– The database we will use is MongoDB which can be accessed by the help of Spring Data MongoDB.
Spring Boot Signup & Login with JWT Authentication Flow
The diagram shows flow of how we implement User Registration, User Login and Authorization process.
A legal JWT must be added to HTTP Authorization Header if Client accesses protected resources.
This app can be used as a back-end that works well with these front-end applications (I’ve tested all of them):
- Vue.js JWT Authentication with Vuex and Vue Router
- Angular 8 JWT Authentication example with Web Api
- Angular 10 JWT Authentication example with Web Api
- Angular 11 JWT Authentication example with Web Api
- Angular 12 JWT Authentication example with Web Api
- Angular 13 JWT Authentication example with Web Api
- React JWT Authentication (without Redux) example
- React Hooks: JWT Authentication (without Redux) example
- React Redux: JWT Authentication example
You can use HttpOnly Cookie for this example instead.
You may need to implement Refresh Token:
More details at: Spring Boot Refresh Token with JWT example
Spring Boot Server Architecture with Spring Security
You can have an overview of our Spring Boot Server with the diagram below:
Let me explain it briefly.
Spring Security
– WebSecurityConfig
is the crux of our security implementation. It configures cors, csrf, session management, rules for protected resources. We can also extend and customize the default configuration that contains the elements below.
(WebSecurityConfigurerAdapter
is deprecated from Spring 2.7.0, you can check the source code for update. More details at:
WebSecurityConfigurerAdapter Deprecated in Spring Boot)
– 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 17 / 11 / 8
- Spring Boot 3 / 2 (with Spring Security, Spring Web, Spring Data JPA)
- jjwt 0.11.5
- MongoDB
- Maven
Project Structure
This is folders & files structure for our Spring Boot application:
security: we configure Spring Security & implement Security Objects here.
WebSecurityConfig
UserDetailsServiceImpl
implementsUserDetailsService
UserDetailsImpl
implementsUserDetails
AuthEntryPointJwt
implementsAuthenticationEntryPoint
AuthTokenFilter
extendsOncePerRequestFilter
JwtUtils
provides methods for generating, parsing, validating JWT
(WebSecurityConfigurerAdapter
is deprecated from Spring 2.7.0, you can check the source code for update. More details at:
WebSecurityConfigurerAdapter Deprecated in Spring Boot)
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 MongoDB MongoRepository
to interact with Database.
UserRepository
extendsMongoRepository<User, String>
RoleRepository
extendsMongoRepository<Role, String>
models defines two main models for Authentication (User
) & Authorization (Role
). They have many-to-many relationship.
User
: id, username, email, password, rolesRole
: id, name
payload defines classes for Request and Response objects
We also have application.properties for configuring Spring Data MongoDB 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:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
Configure Spring Data MongoDB & App properties
Under src/main/resources folder, open application.properties, add these lines.
spring.data.mongodb.database=bezkoder_db
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
# App Properties
bezkoder.app.jwtSecret= ======================BezKoder=Spring===========================
bezkoder.app.jwtExpirationMs= 86400000
Create the models
We’re gonna have 2 collections in database: users & roles.
Let’s define these models.
In models package, create 3 files:
ERole
enum in ERole.java. There are 3 roles corresponding to 3 enum.
package com.bezkoder.spring.jwt.mongodb.models;
public enum ERole {
ROLE_USER,
ROLE_MODERATOR,
ROLE_ADMIN
}
Role
model in Role.java
package com.bezkoder.spring.jwt.mongodb.models;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "roles")
public class Role {
@Id
private String id;
private ERole name;
public Role() {
}
public Role(ERole name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public ERole getName() {
return name;
}
public void setName(ERole name) {
this.name = name;
}
}
User
model in User.java with 5 fields: id, username, email, password, roles.
package com.bezkoder.spring.jwt.mongodb.models;
import java.util.HashSet;
import java.util.Set;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection = "users")
public class User {
@Id
private String id;
@NotBlank
@Size(max = 20)
private String username;
@NotBlank
@Size(max = 50)
@Email
private String email;
@NotBlank
@Size(max = 120)
private String password;
@DBRef
private Set<Role> roles = new HashSet<>();
public User() {
}
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
You can see that we annotate each model with @Document
. The annotation specifies domain object to be persisted to MongoDB.
Implement Repositories
Now, each model above needs a repository for persisting and accessing data. In repository package, we’re gonna create 2 repositories.
UserRepository
There are 3 necessary methods that MongoRepository
supports.
package com.bezkoder.spring.jwt.mongodb.repository;
import java.util.Optional;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.bezkoder.spring.jwt.mongodb.models.User;
public interface UserRepository extends MongoRepository<User, String> {
Optional<User> findByUsername(String username);
Boolean existsByUsername(String username);
Boolean existsByEmail(String email);
}
RoleRepository
This repository also extends MongoRepository
and provides a finder method.
package com.bezkoder.spring.jwt.mongodb.repository;
import java.util.Optional;
import org.springframework.data.mongodb.repository.MongoRepository;
import com.bezkoder.spring.jwt.mongodb.models.ERole;
import com.bezkoder.spring.jwt.mongodb.models.Role;
public interface RoleRepository extends MongoRepository<Role, String> {
Optional<Role> findByName(ERole name);
}
Configure Spring Security
Without WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter
is deprecated from Spring 2.7.0. More details at:
WebSecurityConfigurerAdapter Deprecated in Spring Boot.
In security package, create WebSecurityConfig
class.
WebSecurityConfig.java
package com.bezkoder.spring.jwt.mongodb.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.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.bezkoder.spring.jwt.mongodb.security.jwt.AuthEntryPointJwt;
import com.bezkoder.spring.jwt.mongodb.security.jwt.AuthTokenFilter;
import com.bezkoder.spring.jwt.mongodb.security.services.UserDetailsServiceImpl;
@Configuration
//@EnableWebSecurity
@EnableMethodSecurity
//(securedEnabled = true,
//jsr250Enabled = true,
//prePostEnabled = true) // by default
public class WebSecurityConfig { // extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception {
return authConfig.getAuthenticationManager();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth.requestMatchers("/api/auth/**").permitAll().requestMatchers("/api/test/**")
.permitAll().anyRequest().authenticated());
http.authenticationProvider(authenticationProvider());
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
With WebSecurityConfigurerAdapter
In security package, create WebSecurityConfig
class that extends WebSecurityConfigurerAdapter
.
WebSecurityConfig.java
package com.bezkoder.spring.jwt.mongodb.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.bezkoder.spring.jwt.mongodb.security.jwt.AuthEntryPointJwt;
import com.bezkoder.spring.jwt.mongodb.security.jwt.AuthTokenFilter;
import com.bezkoder.spring.jwt.mongodb.security.services.UserDetailsServiceImpl;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@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()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
– @EnableWebSecurity
allows Spring to find and automatically apply the class to the global Web Security.
*For Spring Boot 2: @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.
– @EnableGlobalMethodSecurity
is deprecated in Spring Boot 3. You can use @EnableMethodSecurity
instead. For more details, please visit Method Security.
– 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.
Authentication authentication =
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)
);
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
// userDetails.getUsername()
// userDetails.getPassword()
// userDetails.getAuthorities()
If we want to get more data (id, email…), we can create an implementation of this UserDetails
interface.
security/services/UserDetailsImpl.java
package com.bezkoder.spring.jwt.mongodb.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.bezkoder.spring.jwt.mongodb.security.jwt.AuthEntryPointJwt;
import com.bezkoder.spring.jwt.mongodb.security.jwt.AuthTokenFilter;
import com.bezkoder.spring.jwt.mongodb.security.services.UserDetailsServiceImpl;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
// securedEnabled = true,
// jsr250Enabled = true,
prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Autowired
private AuthEntryPointJwt unauthorizedHandler;
@Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
@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()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
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.
UserDetailsService
will be used for getting UserDetails
object. You can look at UserDetailsService
interface that has following method:
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
Now we implement it to override loadUserByUsername()
method.
security/services/UserDetailsServiceImpl.java
package com.bezkoder.spring.jwt.mongodb.security.services;
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;
import com.bezkoder.spring.jwt.mongodb.models.User;
import com.bezkoder.spring.jwt.mongodb.repository.UserRepository;
@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: " + username));
return UserDetailsImpl.build(user);
}
}
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
package com.bezkoder.spring.jwt.mongodb.security.jwt;
import java.io.IOException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.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.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import com.bezkoder.spring.jwt.mongodb.security.services.UserDetailsServiceImpl;
public class AuthTokenFilter extends OncePerRequestFilter {
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailsServiceImpl userDetailsService;
private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
try {
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.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("Cannot set user authentication: {}", e);
}
filterChain.doFilter(request, response);
}
private String parseJwt(HttpServletRequest request) {
String headerAuth = request.getHeader("Authorization");
if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
return headerAuth.substring(7, headerAuth.length());
}
return null;
}
}
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:
UserDetails userDetails =
(UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
// userDetails.getUsername()
// userDetails.getPassword()
// userDetails.getAuthorities()
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
package com.bezkoder.spring.jwt.mongodb.security.jwt;
import java.security.Key;
import java.util.Date;
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.bezkoder.spring.jwt.mongodb.security.services.UserDetailsImpl;
import com.bezkoder.spring.jwt.mongodb.security.jwt.JwtUtils;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
@Component
public class JwtUtils {
private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
@Value("${bezkoder.app.jwtSecret}")
private String jwtSecret;
@Value("${bezkoder.app.jwtExpirationMs}")
private int jwtExpirationMs;
public String generateJwtToken(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
return Jwts.builder()
.setSubject((userPrincipal.getUsername()))
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(key(), SignatureAlgorithm.HS256)
.compact();
}
private Key key() {
return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
}
public String getUserNameFromJwtToken(String token) {
return Jwts.parserBuilder().setSigningKey(key()).build()
.parseClaimsJws(token).getBody().getSubject();
}
public boolean validateJwtToken(String authToken) {
try {
Jwts.parserBuilder().setSigningKey(key()).build().parse(authToken);
return true;
} catch (MalformedJwtException e) {
logger.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
logger.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
logger.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
logger.error("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}
Remember that we’ve added bezkoder.app.jwtSecret
and bezkoder.app.jwtExpirationMs
properties in application.properties
file, and jwtSecret
has 64 characters.
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
package com.bezkoder.spring.jwt.mongodb.security.jwt;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.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 AuthEntryPointJwt implements AuthenticationEntryPoint {
private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
logger.error("Unauthorized error: {}", authException.getMessage());
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Error: Unauthorized");
}
}
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 }
I don’t show these POJOs here for keeping the tutorial not so long,
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
(withROLE_USER
if not specifying role) - save
User
to database usingUserRepository
– /api/auth/signin
- authenticate { username, pasword }
- update
SecurityContext
usingAuthentication
object - generate
JWT
- get
UserDetails
fromAuthentication
object - response contains
JWT
andUserDetails
data
controllers/AuthController.java
package com.bezkoder.spring.jwt.mongodb.controllers;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import jakarta.validation.Valid;
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.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.bezkoder.spring.jwt.mongodb.models.ERole;
import com.bezkoder.spring.jwt.mongodb.models.Role;
import com.bezkoder.spring.jwt.mongodb.models.User;
import com.bezkoder.spring.jwt.mongodb.payload.request.LoginRequest;
import com.bezkoder.spring.jwt.mongodb.payload.request.SignupRequest;
import com.bezkoder.spring.jwt.mongodb.payload.response.JwtResponse;
import com.bezkoder.spring.jwt.mongodb.payload.response.MessageResponse;
import com.bezkoder.spring.jwt.mongodb.repository.RoleRepository;
import com.bezkoder.spring.jwt.mongodb.repository.UserRepository;
import com.bezkoder.spring.jwt.mongodb.security.jwt.JwtUtils;
import com.bezkoder.spring.jwt.mongodb.security.services.UserDetailsImpl;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Autowired
PasswordEncoder encoder;
@Autowired
JwtUtils jwtUtils;
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
@PostMapping("/signup")
public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {
if (userRepository.existsByUsername(signUpRequest.getUsername())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Username is already taken!"));
}
if (userRepository.existsByEmail(signUpRequest.getEmail())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Email is already in use!"));
}
// Create new user's account
User user = new User(signUpRequest.getUsername(),
signUpRequest.getEmail(),
encoder.encode(signUpRequest.getPassword()));
Set<String> strRoles = signUpRequest.getRoles();
Set<Role> roles = new HashSet<>();
if (strRoles == null) {
Role userRole = roleRepository.findByName(ERole.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(userRole);
} else {
strRoles.forEach(role -> {
switch (role) {
case "admin":
Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(adminRole);
break;
case "mod":
Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(modRole);
break;
default:
Role userRole = roleRepository.findByName(ERole.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(userRole);
}
});
}
user.setRoles(roles);
userRepository.save(user);
return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
}
}
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)
(or @EnableMethodSecurity
for Spring Boot 3) in WebSecurityConfig
class?
@Configuration
// @EnableWebSecurity
// @EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity // Spring Boot 3
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { ... }
Now we can secure methods in our Apis with @PreAuthorize
annotation easily.
controllers/TestController.java
package com.bezkoder.spring.jwt.mongodb.controllers;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/test")
public class TestController {
@GetMapping("/all")
public String allAccess() {
return "Public Content.";
}
@GetMapping("/user")
@PreAuthorize("hasRole('USER') or hasRole('MODERATOR') or hasRole('ADMIN')")
public String userAccess() {
return "User Content.";
}
@GetMapping("/mod")
@PreAuthorize("hasRole('MODERATOR')")
public String moderatorAccess() {
return "Moderator Board.";
}
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminAccess() {
return "Admin Board.";
}
}
Run & Test
Run Spring Boot application with command: mvn spring-boot:run
We also need to add some rows into roles collection before assigning any role to User.
Run following MongoDB insert statements:
db.roles.insertMany([
{ name: "ROLE_USER" },
{ name: "ROLE_MODERATOR" },
{ name: "ROLE_ADMIN" },
])
Then check the MongoDB collections:
Register some users with /signup
API:
- admin with
ROLE_ADMIN
- moderator with
ROLE_MODERATOR
andROLE_USER
- bezkoder with
ROLE_USER
After make some user registration, users
collection could look like this-
Access public resource: GET /api/test/all
Access protected resource: GET /api/test/user
Login an account: POST /api/auth/signin
Access ROLE_USER
resource: GET /api/test/user
Access ROLE_MODERATOR
resource: GET /api/test/mod
Access ROLE_ADMIN
resource: GET /api/test/admin
Solve Problem: javax.validation cannot be resolved
For Spring Boot 2.3 and later, you can see the compile error:
The import javax.validation cannot be resolved
It is because Validation Starter no longer included in web starters. So you need to add the starter yourself.
– For Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
– For Gradle:
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
Problem with newer JDK
If you run this Spring Boot App with JDK 9 or newer versions and get following error when trying to authenticate:
FilterChain java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
Just add following dependency to pom.xml:
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>2.3.2</version>
</dependency>
Everything’s gonna work fine.
Conclusion
Oh Yeah! Today we’ve learned many things about Spring Security and JWT Token based Authentication in a Spring Boot MongoDB login & registration example (with Authorization).
This app can be used as a back-end that works well with these front-end applications (I’ve tested all of them):
- Vue.js JWT Authentication with Vuex and Vue Router
- Angular 8 JWT Authentication example with Web Api
- Angular 10 JWT Authentication example with Web Api
- Angular 11 JWT Authentication example with Web Api
- Angular 12 JWT Authentication example with Web Api
- Angular 13 JWT Authentication example with Web Api
- React JWT Authentication (without Redux) example
- React Hooks: JWT Authentication (without Redux) example
- React Redux: JWT Authentication example
Happy learning! See you again.
You should continue to know how to implement Refresh Token:
Spring Boot Refresh Token with JWT example
Further Reading
- In-depth Introduction to JWT-JSON Web Token
- Spring Security Reference
- Spring Data MongoDB – Reference Documentation
Fullstack CRUD App:
- Angular 8 + Spring Boot + MongoDB example
- Angular 10 + Spring Boot + MongoDB example
- Angular 11 + Spring Boot + MongoDB example
- Angular 12 + Spring Boot + MongoDB example
- Angular 13 + Spring Boot + MongoDB example
- Angular 14 + Spring Boot + MongoDB example
- Angular 15 + Spring Boot + MongoDB example
- Angular 16 + Spring Boot + MongoDB example
- React + Spring Boot + MongoDB example
- Vue + Spring Boot + MongoDB example
Documentation: Spring Boot + Swagger 3 example (with OpenAPI 3)
Caching: Spring Boot Redis Cache example
Dockerize: Docker Compose: MongoDB and Spring Boot example
Source Code
You can find the complete source code for this tutorial on Github.
You can also use HttpOnly Cookie for this example.
Validate the signup request (password, confirm password):
Spring Boot custom Validation example
When I try to enter with JWT token in /api/test/user Postman gives me a 403 Forbiden error. Where can be possible the error??
Hi, maybe you forgot to set the Bearer Token on your HTTP request.
Thank you so much I was days and days trying to solve how to put a controller to made a login in my API.
Users and roles are created successfully, but I have usually this error when I try to access to http://localhost:8099/api/test/user?Authorization=Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhYmlkaTEyMzQ1IiwiaWF0IjoxNjQwMTE3OTk1LCJleHAiOjE2NDAyMDQzOTV9.b3aCQys6hMYiWNGpi4PVsjRfkv8NsyKq6C6B5hPC4T6JD0P3BYGjlu8OqfaoFCP6YkCcg6OtTLQVHuE-G_qcFw
Hi, you need to add Bearer token into your HTTP request Header, not request params :)
thnx it works :)
Hello, First of all thanks for the tutorial, as a newcomer in spring boot it really helps.
Tho I have an error when trying to run my spring app, and I have trouble understanding what is going on, and how to fix it.
The error message is something like this :
2021-11-12 15:35:40.261 ERROR 19252 — [ main] o.s.b.web.embedded.tomcat.TomcatStarter : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name ‘webSecurityConfig’: Unsatisfied dependency expressed through field ‘userDetailsService’; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘userDetailsServiceImpl’ defined in file [C:\Users\fkuhl\Workflow\SpringCourse\target\classes\com\Thiiamas\SpringCourse\Security\Services\UserDetailsServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘userRepository’ defined in com.Thiiamas.SpringCourse.Repository.UserRepository defined in @EnableMongoRepositories declared on MongoRepositoriesRegistrar.EnableMongoRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.lang.Boolean com.Thiiamas.SpringCourse.Repository.UserRepository.existByUsername(java.lang.String)! Reason: No property existByUsername found for type User!; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property existByUsername found for type User!
I tried adding “@Repository” annotation to the repositiory, I also generated a constructor on UserDetailsImpl, but it doesn’t really help.
If you could help me, or explaining what is going on please ! I’m really new to everything server side so i’m kinda lost.
Florian
I added a constructor to “UserDetailsServiceImpl” not “UserdetailsImpl”*
Dude, You are a lifesaver. Your tutorials are the same as official documents and you follow best practices. thank you!
2021-09-29 15:56:23.793 ERROR 15380 — [nio-8084-exec-4] c.b.s.j.m.s.jwt.AuthEntryPointJwt : Unauthorized error: Full authentication is required to access this resource
please help me
Hi, please check your Authorization Header with correct Bearer Token.
Users and roles are created successfully
I have usually this error when I try to access http://localhost:8099/api/test/user?Authorization=Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhYmlkaTEyMzQ1IiwiaWF0IjoxNjQwMTE3OTk1LCJleHAiOjE2NDAyMDQzOTV9.b3aCQys6hMYiWNGpi4PVsjRfkv8NsyKq6C6B5hPC4T6JD0P3BYGjlu8OqfaoFCP6YkCcg6OtTLQVHuE-G_qcFw
Thank you , I am looking forwarding learning more from this tutorials.
Thanks for the explanation.
How would you tackle the issue that everyone would be able to add an admin role to their account when using postman to create it (e.g. when they figure out the endpoint to create a new account via networks tab in chrome).
Thanks!
I’ve got this working as far as I can create a user. But when I try to login I get an error in the console:
“Encoded password does not look like BCrypt”
I can see the password is stored as “$2a$10$vjr9VD7P.qPwbxoL66XC1e9AsW9OZUIGXyKBZ0mXW6tdsofcEdnU.” which looks valid to me.
Is there anything obvious this could be?
http://localhost:8080/api/test/user
This link is giving 401 unauthorized error, Please help
Hi, you need to make
signin
request first, then use the token for accessingtest/user
.hi sir,
All functions are working fine! but when I login as the moderator, the dashboard displays ”Moderator Board” and “User”. when I click one of these option, I can see error “Error: Unauthorized” (I used frontend for your React JWT Authentication (without Redux) example )
and also throwing error in spring boot console –
” ERROR[0;39m [35m18012[0;39m [2m—[0;39m [2m[nio-8080-exec-2][0;39m [36mc.b.s.j.m.s.jwt.AuthEntryPointJwt [0;39m [2m:[0;39m Unauthorized error: Full authentication is required to access this resource”
when I remove @PreAuthorize(“hasAuthority(‘MODERATOR’)”) it is working.. but that way anyone can access right? I actually find out many ways and try but it didn’t work.
would you mind giving me a solution for that sir!
Thank you very much!
I found the error where is sir! the error occurred frontend auth-header.js file. actually not an error that spring boot return access token method is commented and node js access token return is enabled. that’s the case.
thank you!
can you clarify more please cause i have the same error as you
Hi,
I have tried to implement it using dynamodb instead of mongodb. I am getting 401 Unauthorized for all requests.
Have created the roles table , inserted the roles as well.
Any idea?
Thank You so much ; )
Dude, I am working as a trainee in a company and we are forced to work on case study without any training, we are just left to study from youtube and finally got you. You literally saved me. Thanks Once again.
I’m so happy to know that my work helps people like you :)
hi and thanks you very much but when i try to sing in i get this message Unauthorized error: Failed to instantiate com.example.Educart.models.User using constructor NO_CONSTRUCTOR with arguments pls can you help me up
Hi, please check your code with Github source code :)
While hitting this api http://localhost:8080/api/auth/signup.
everytime its asking for username password in the popup menu. I havent created the user then why its asking for credentials.
It works but when I try to use the other controllers developed by me it seems all autowired classes are null. Do you have any idea why ?
I found the problem. It seems some methods were declared private. Changing to public solved the problem.
My mistake with 401 – made roles as a new db instead of a collection of users_db.
thanks to people like you the world is a better place
This article was very useful. Thank you.
how to implement email verification for user
I’m getting “Unauthorized User” 401 error on signup and signin requests. Can you please tell me what can be the possible issue? Thanks in advance.
Same for me
Hi Elie, the possible issue can be that you are using a different role name instead of the ROLE_ADMIN or ROLE_MODERATOR … the roles got to be with the ROLE_ prefix like in the tutorial… other thing is that when you try to access admin-restricted endpoint you got to generate the token and use the authorization header with this value … “Bearer oajjsodijoi3jijdoiajd2dioajsd”
oajjsodijoi3jijdoiajd2dioajsd mean your access token that was generated. Hope it helps someone… if you are struggling with this tutorial please send me a message and i will help you.
My email is [email protected]
Have a nice day.
Hi Jones. when i am using the signup api . its asking for username password. Not sure why , can you please help.
This tutorial saved my life! The only one absolutely complete and clear.
Thank You!
for a class WebSecurityConfig extends WebSecurityConfigurerAdapter
a method with configure shows the following error as
The method userDetailsService(T) in the type AuthenticationManagerBuilder is not applicable for the arguments (UserDetailsImpl) at line authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
I encountered the same error but I realized I did implement the interface on UserDetailsService on my source project instead of referencing the one in the spring library. After deleting UserDetailsService.java I mistakenly created, and referenced the one in the Spring security library, I did not get the errors anymore.
When running under JDK 9/10/11, add these dependencies to your pom file to prevent class not found errors:
jakarta.xml.bind
jakarta.xml.bind-api
2.3.2
org.glassfish.jaxb
jaxb-runtime
2.3.2
Can we use the email in place of username, because like you know apps are modified the way the client want, what if he don’t want a username
Hi, Can i use this reference with Couchbase DB, If yes then how can i add predefined ROLE
Hello Guys ! When you are using the authentication URL: / api / auth / signin and a conversion error occurs you will need to include these libraries in the project, this problem occurred to me, I am forwarding it in case anyone needs help with this problem.
jakarta.xml.bind
jakarta.xml.bind-api
org.glassfish.jaxb
jaxb-runtime
Thanks. This was very helpful. Great work!
Thank you for the tutorial. Very detailed and appreciate the visuals.
I’m getting an error when attempting to POST a request for api/auth/signin using Postman.
{
“message”: “Handler dispatch failed; nested exception is java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter”,
“details”: “uri=/api/v1/auth/signin”
}
My research points to a parse error linked to the xml conversion of the data using DatatypeConverter class. I’m using java 8 and believe the dependency module is included.
Tried importing the DatatypeConvert class in JwtUtils class to parse the secret key but still getting the error. Hopefully you have some ideas? Thank you in advance.
// get username from JWT
public String getUserNameFromJwtToken(String token) {
return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(jwtSecret)).parseClaimsJws(token).getBody().getSubject();
}
// validate a JWT
public boolean validateJwtToken(String authToken) {
try {
Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(jwtSecret)).parseClaimsJws(authToken);
return true;
}
…
}
Managed to solve this issue. Added the following dependencies. I’m running JDK 8.
javax.xml.bind
jaxb-api
com.sun.xml.bind
jaxb-impl
2.3.0
com.sun.xml.bind
jaxb-core
2.3.0
javax.activation
activation
1.1.1
Iam using JDK 11 and only had to add jaxb-api
javax.xml.bind
jaxb-api
2.3.1
Thank you :D I had this problem too.
I suppose that the collections roles and users would be auto created after running the project.
But that’s not the case, can you please explain why?
By default, MongoDb collection will be created when you create a document.
Thanks a lot for your tutorial. May I know How to implement log-out functionality? Also, How to retrieve email Id from Authentication principal UserDetails?
Hi,
– for logout in Spring back-end:
- for Email, you can use
UserDetailsImpl
:You mean something like this?
Yes, also clear localStorage/Cookies if you stored token in that.
This snippet doesn’t work. The token stay working.
s’il vous plait comment on gère la le mot de passe oublié ,comment récupérer le mail ,ici j’ai vu que t’as pas déclaré authentification pour faire getPrincipale ()
Hi, I do not understand why do we have to call logout in the backend. I’m new to this. Don’t we just clear local storage or cookies, and that’s enough? Please correct me if I’m wrong. Thank you.
Hello! Please may you implement “Password Reset” functionality, however I’m looking for a guide to follow. I’ve searched but I didn’t found it I’m always found jwt using another tool.
So can you plan a serie on that topic.
Best regards.
Thanks a lot!!!
Hi i am getting error {“timestamp”:”2020-04-16T06:20:27.849+0000″,”status”:500,”error”:”Internal Server Error”,”message”:”Error: Role is not found.”,”path”:”/api/auth/signup”}
Hi, what is the payload? And did you set
'Content-Type': 'application/json'
for HTTP request Header?Hi I’m also getting this error
{“timestamp”: “2020-10-19T07:22:47.901+00:00”,
“status”: 500,
“error”: “Internal Server Error”,
“message”: “”,
“path”: “/api/auth/signup”}
so what is the solution for this
Hi!
I faced this problem even I insert ROLE into roles document so please can you help me
Error: Role is not found.
How did the issue occur? Please show me the error log :)
I fixed the issue thank you for your reply :)
Hi, I faced the same error , can you tell me how did you fixed it ?
Sorry I just saw your comment you should first insert roles into your database then problem fixed
Hi, i did as below and worked:
i use mongodb compass app ,
first creat new database “bezkoder_db” with colleciton”roles”
then use bottom >_mongodsh beta , type: use roles
then copy paste the insert command i
bro can u solve my error role not found….. even though i created the roles in database…..
i faced the some error even when i add role to my base can you help me please
Thank you for this tutorial. It is well written and very useful.
Thank you for this tutorial. Very well explained.
I have a doubt in reactjs that how we can register with roles.I tried by using dropdown select option but im not getting the exact output.can you give some idea for login ,logout, registration with roles using JWT
Hi, I’ll write a tutorial for React front-end using JWT for Auth when having time. You can refer following tutorial:
React JWT Authentication (without Redux) example
hi,
i have a doubt in these part…
when if part executes.i checked in postman if am giving null the role user is not saved .can u pls explain these briefly
Hi, I think you forgot to run following MongoDB insert statements:
I am new to mongoDb and I am getting below error
Error: Role is not found.
I have already run insert statement in cmd
comma at the end of json object in array will result in syntax error.
i am getting an error like “ROLE is not found” .. i have done all the steps
2020-06-11 16:42:32.272 ERROR 13972 — [nio-8089-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: Error: Role is not found.] with root cause
java.lang.RuntimeException: Error: Role is not found.
I am getting above error message, I have already inserted role.