Spring Boot app with Spring Security (JWT) and MySQL database
JavaSpring Boot app with Spring Security (JWT) and MySQL database.
In this tutorial, we will explore the implementation of token-based authentication in a Spring Boot application using Spring Security, JWT, and MySQL database with a Refresh Token.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.2.2</version>
</dependency>
</dependencies>
Configure MySQL Database
create database springtest
spring.datasource.driver-class-name =com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/springtest spring.datasource.username=root spring.datasource.password=mysql spring.jpa.show-sql=true spring.jpa.generate-ddl=true spring.jpa.hibernate.ddl-auto=create spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.properties.hibernate.formart_sql=true jwt.expiration=60000 jwt.secret=mySecret jwt.refreshToken.expiration=120 logging.level.org.springframework.security=DEBUG
Model Layer - Create JPA Entities
JwtUser
import lombok.*; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import javax.persistence.*; import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.UUID; @EqualsAndHashCode(of = "uuid") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor @Entity public class JwtUser implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Builder.Default private String uuid = UUID.randomUUID().toString(); @Column private String username; @Column(unique = true) private String email; @Column private String password; @Column @Enumerated(EnumType.STRING) @ElementCollection(fetch = FetchType.EAGER) private Set<Role> role = new HashSet<>(); @Column @Builder.Default private boolean enabled = false; @OneToOne(mappedBy = "user") private RefreshToken refreshToken; @Override public Collection<? extends GrantedAuthority> getAuthorities() { Set<GrantedAuthority> authorities = new HashSet<>(); for (var r : this.role) { var sga = new SimpleGrantedAuthority(r.name()); authorities.add(sga); } 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 this.enabled; } }
Role
public enum Role {
ROLE_USER,
ROLE_ADMIN,
ROLE_API
}
RefreshToken
import lombok.*; import javax.persistence.*; import java.time.ZonedDateTime; import java.util.UUID; @EqualsAndHashCode(of = "uuid") @Getter @Setter @Builder @NoArgsConstructor @AllArgsConstructor @Entity public class RefreshToken { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Builder.Default private String uuid = UUID.randomUUID().toString(); @Column private String token; @Column private ZonedDateTime expiration; @OneToOne @JoinColumn(nullable = false, name = "user_id") private JwtUser user; }
Repository Layer
JwtUserRepository
import com.samdev.mulikevs.rolebased_jwt.entity.JwtUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface JwtUserRepository extends JpaRepository<JwtUser, Long> {
Optional<JwtUser> findJwtUserByUsername(String username);
Optional<JwtUser> findJwtUserByEmail(String email);
}
RefreshTokenRepository
import com.samdev.mulikevs.rolebased_jwt.entity.RefreshToken; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.Optional; @Repository public interface RefreshTokenRepository extends JpaRepository<RefreshToken, Long> { Optional<RefreshToken> findRefreshTokenByToken(String token); }
JWT Implementation
SecurityBeans
Let's create SecurityBeans class and add the following code to it:
import lombok.SneakyThrows; import org.springframework.context.annotation.Bean; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @Component public class SecurityBeans { @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @SneakyThrows @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) { return authenticationConfiguration.getAuthenticationManager(); } }
The SecurityBeans class serves the purpose of providing essential security-related beans and configurations for a Spring Boot application. It is responsible for defining and creating two beans: passwordEncoder()
, which returns an instance of BCryptPasswordEncoder
used for password hashing, and authenticationManager()
, which retrieves the authentication manager configured in the Spring Security framework. By utilizing these beans, the class contributes to setting up the necessary components for password encoding and authentication management within the application's Spring Security configuration
JTW Utility Class - JwtUtils.java
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; @Component @RequiredArgsConstructor public class JwtUtils { @Value("${jwt.expiration}") private int expTime; @Value("${jwt.secret}") private String secret; public String createJwt(String email) { return JWT.create() .withSubject(email) .withExpiresAt(Instant.ofEpochMilli(ZonedDateTime.now(ZoneId.systemDefault()).toInstant().toEpochMilli() + expTime)) .sign(Algorithm.HMAC256(secret)); } }
JwtRefreshRequestDto Class
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class JwtRefreshRequestDto {
private String refreshToken;
}
JwtResponseDto Class
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @AllArgsConstructor @NoArgsConstructor @Getter @Setter public class JwtResponseDto { private String token; private String refreshToken; public static JwtResponseDto of(String token, String refreshToken) { return new JwtResponseDto(token, refreshToken); } }
LoginCredentials Class
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginCredentials {
private String email;
private String password;
}
AuthSuccessHandler
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.samdev.mulikevs.rolebased_jwt.security.domain.JwtResponseDto;
import com.samdev.mulikevs.rolebased_jwt.service.JwtUserService;
import com.samdev.mulikevs.rolebased_jwt.service.RefreshTokenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@Component
@Slf4j
@RequiredArgsConstructor
public class AuthSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final ObjectMapper objectMapper = new ObjectMapper();
private final JwtUserService jwtUserService;
private final JwtUtils jwtUtils;
private final RefreshTokenService refreshTokenService;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
UserDetails principal = (UserDetails) authentication.getPrincipal();
var user = jwtUserService.getJwtUserByUsername(principal.getUsername());
String token = jwtUtils.createJwt(user.getEmail());
String refreshToken = refreshTokenService.createToken(user);
response.addHeader("Authorization", "Bearer " + token);
response.addHeader("Content-Type", "application/json");
response.getWriter().write(objectMapper.writeValueAsString(JwtResponseDto.of(token, refreshToken)));
}
}
JsonObjectAuthenticationFilter
import com.fasterxml.jackson.databind.ObjectMapper;
import com.samdev.mulikevs.rolebased_jwt.security.domain.LoginCredentials;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
//http://172.16.19.15/syscbiuat/en/coop_bank/cases/main
@Slf4j
public class JsonObjectAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
try {
BufferedReader reader = request.getReader();
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
LoginCredentials authRequest = objectMapper.readValue(sb.toString(), LoginCredentials.class);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
authRequest.getEmail(), authRequest.getPassword()
);
log.info("Testing Here ####################################");
setDetails(request, token);
return this.getAuthenticationManager().authenticate(token);
} catch (IOException e) {
log.info("Failed Here ####################################"+e+"###################################");
throw new RuntimeException(e);
}
}
}
Let's create JwtAuthenticationFilter class in a Spring Boot application that intercepts incoming HTTP requests and validates JWT tokens that are included in the Authorization header. If the token is valid, the filter sets the current user's authentication in the SecurityContext.
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.samdev.mulikevs.rolebased_jwt.service.JwtUserDetailsService; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; 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.www.BasicAuthenticationFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JwtAuthorizationFilter extends BasicAuthenticationFilter { private static final String TOKEN_PREFIX = "Bearer "; private final JwtUserDetailsService jwtUserDetailsService; private final String secret; public JwtAuthorizationFilter(AuthenticationManager authenticationManager, JwtUserDetailsService jwtUserDetailsService, String secret) { super(authenticationManager); this.jwtUserDetailsService = jwtUserDetailsService; this.secret = secret; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { UsernamePasswordAuthenticationToken auth = getAuthentication(request); if (auth==null) { filterChain.doFilter(request, response); return; } SecurityContextHolder.getContext().setAuthentication(auth); filterChain.doFilter(request, response); } private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) { String token = request.getHeader(HttpHeaders.AUTHORIZATION); if (token == null || !token.startsWith(TOKEN_PREFIX)) { return null; } String email = JWT.require(Algorithm.HMAC256(secret)) .build() .verify(token.replace(TOKEN_PREFIX, "")) .getSubject(); if (email == null) return null; UserDetails userDetails = jwtUserDetailsService.loadUserByUsername(email); return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities()); } }
Here's a breakdown of the key parts of the above code:
The class
JwtAuthorizationFilter
extendsBasicAuthenticationFilter
, which is a class provided by Spring Security to handle basic authentication filtering.The class has a constructor that takes an
AuthenticationManager
object, aJwtUserDetailsService
object, and a secret as parameters. These dependencies are injected into the filter.- The
doFilterInternal
method is overridden to perform the authorization logic. It extracts the token from the request'sAuthorization
header, verifies and decodes the token using the provided secret, retrieves the email from the token, and loads the user details from theJwtUserDetailsService
. Finally, it sets the authentication in theSecurityContextHolder
and continues the filter chain The
getAuthentication
method is responsible for extracting the token from the request header, verifying and decoding it using the provided secret, and retrieving the email from the token. It then loads the user details from theJwtUserDetailsService
and creates anUsernamePasswordAuthenticationToken
object with the username, null password, and user authorities.If the token is not present or doesn't start with the expected prefix, the
getAuthentication
method returns null, indicating that no authentication should be performed.
JwtCustomSecurity Class
import com.samdev.mulikevs.rolebased_jwt.service.JwtUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
@Configuration
public class JwtCustomSecurity {
@Autowired
private AuthenticationManager authenticationManager;
private final AuthSuccessHandler authSuccessHandler;
private final JwtUserDetailsService jwtUserDetailsService;
private final String secret;
public JwtCustomSecurity(AuthSuccessHandler authSuccessHandler, JwtUserDetailsService jwtUserDetailsService, @Value("${jwt.secret}") String secret) {
this.authSuccessHandler = authSuccessHandler;
this.jwtUserDetailsService = jwtUserDetailsService;
this.secret = secret;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.authorizeHttpRequests((auth) -> {
try {
auth
.antMatchers("/user").hasRole("USER")
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/api").hasRole("API")
.anyRequest().permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(authenticationFilter())
.addFilter(new JwtAuthorizationFilter(authenticationManager, jwtUserDetailsService, secret))
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
public JsonObjectAuthenticationFilter authenticationFilter() throws Exception {
JsonObjectAuthenticationFilter filter = new JsonObjectAuthenticationFilter();
filter.setAuthenticationSuccessHandler(authSuccessHandler);
filter.setAuthenticationManager(authenticationManager);
return filter;
}
}
The provided code represents a configuration class JwtCustomSecurity
that sets up the security configuration for JWT-based authentication in a Spring Boot application.
JwtCustomSecurity
that sets up the security configuration for JWT-based authentication in a Spring Boot application.Controller Layer - Refresh token REST API return JWT Token
Let's create an AuthController class and add the following code to it:
import com.samdev.mulikevs.rolebased_jwt.security.domain.JwtRefreshRequestDto;
import com.samdev.mulikevs.rolebased_jwt.security.domain.JwtResponseDto;
import com.samdev.mulikevs.rolebased_jwt.service.RefreshTokenService;
import lombok.RequiredArgsConstructor;
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;
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {
private final RefreshTokenService refreshTokenService;
@PostMapping("/refresh")
public JwtResponseDto refreshJwt(@RequestBody JwtRefreshRequestDto refreshRequestDto) {
return refreshTokenService.refreshToken(refreshRequestDto);
}
}
Controller Layer - Refresh token REST API return JWT Token
Let's create an AuthController class and add the following code to it:
import com.samdev.mulikevs.rolebased_jwt.security.domain.JwtRefreshRequestDto;
import com.samdev.mulikevs.rolebased_jwt.security.domain.JwtResponseDto;
import com.samdev.mulikevs.rolebased_jwt.service.RefreshTokenService;
import lombok.RequiredArgsConstructor;
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;
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {
private final RefreshTokenService refreshTokenService;
@PostMapping("/refresh")
public JwtResponseDto refreshJwt(@RequestBody JwtRefreshRequestDto refreshRequestDto) {
return refreshTokenService.refreshToken(refreshRequestDto);
}
}
Controller Layer - TestController
Let's create an TestController class and add the following code to it:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/user")
public TestMessage userEndpoint() {
return new TestMessage("Hello user!");
}
@GetMapping("/admin")
public TestMessage adminEndpoint() {
return new TestMessage("Hello admin!");
}
@GetMapping("/api")
public TestMessage apiEndpoint() {
return new TestMessage("Hello Api!");
}
}
TestMessage
Let's create an TestMessage class and add the following code to it:
import lombok.Value;
@Value
public class TestMessage {
String msg;
}
import lombok.Value;
@Value
public class TestMessage {
String msg;
}
InitUsers
Let's create an InitUsers class and add the following code to it: This will create the default users.
import com.samdev.mulikevs.rolebased_jwt.entity.JwtUser;
import com.samdev.mulikevs.rolebased_jwt.entity.Role;
import com.samdev.mulikevs.rolebased_jwt.service.JwtUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
@RequiredArgsConstructor
public class InitUsers implements CommandLineRunner {
private final JwtUserService jwtUserService;
private final PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
if (jwtUserService.findJwtUserByEmail("admin@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("Admin")
.email("admin@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_ADMIN, Role.ROLE_USER))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
if (jwtUserService.findJwtUserByEmail("user@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("User")
.email("user@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_USER))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
if (jwtUserService.findJwtUserByEmail("api@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("apiUser")
.email("api@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_API))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
}
}
import com.samdev.mulikevs.rolebased_jwt.entity.JwtUser;
import com.samdev.mulikevs.rolebased_jwt.entity.Role;
import com.samdev.mulikevs.rolebased_jwt.service.JwtUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.CommandLineRunner;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import java.util.Set;
@Component
@RequiredArgsConstructor
public class InitUsers implements CommandLineRunner {
private final JwtUserService jwtUserService;
private final PasswordEncoder passwordEncoder;
@Override
public void run(String... args) throws Exception {
if (jwtUserService.findJwtUserByEmail("admin@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("Admin")
.email("admin@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_ADMIN, Role.ROLE_USER))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
if (jwtUserService.findJwtUserByEmail("user@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("User")
.email("user@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_USER))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
if (jwtUserService.findJwtUserByEmail("api@test.com").isEmpty()) {
JwtUser u = jwtUserService.save(JwtUser.builder()
.username("apiUser")
.email("api@test.com")
.password(passwordEncoder.encode("test123"))
.role(Set.of(Role.ROLE_API))
.build());
u.setEnabled(true);
jwtUserService.save(u);
}
}
}
Run & Test
Run Spring Boot application with command: mvn spring-boot:run
Login and Refresh Token
http://localhost:8080/login
Request:
{"email":"api@test.com","password":"test123"}
Response:
{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcGlAdGVzdC5jb20iLCJleHAiOjE2ODUwMTk3NjJ9.dlsK9pmjXOxZQQbNWcr7_IcIZFXAvzMUkkfiud_-onY", "refreshToken": "cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
http://localhost:8080/login
Request:
{"email":"api@test.com","password":"test123"}
Response:
{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcGlAdGVzdC5jb20iLCJleHAiOjE2ODUwMTk3NjJ9.dlsK9pmjXOxZQQbNWcr7_IcIZFXAvzMUkkfiud_-onY", "refreshToken": "cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
http://localhost:8080/auth/refresh
Request:
{"refreshToken":"cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
Response:
{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcGlAdGVzdC5jb20iLCJleHAiOjE2ODUwMTk4ODB9.mljItw05MUGsOk_F0oo3GuWzVWOywUMQVWhbJ_x1Hmg", "refreshToken": "cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
http://localhost:8080/auth/refresh
Request:
{"refreshToken":"cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
Response:
{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhcGlAdGVzdC5jb20iLCJleHAiOjE2ODUwMTk4ODB9.mljItw05MUGsOk_F0oo3GuWzVWOywUMQVWhbJ_x1Hmg", "refreshToken": "cb2a4ad8-37c5-4eb0-961a-89802af54a86"}
The code can be accessed from git rolebased_jwt
Spring Boot app with Spring Security (JWT) and MySQL database
May 26, 2023