Spring Boot app with Spring Security (JWT) and MySQL database

Spring Boot app with Spring Security (JWT) and MySQL database

Java

Spring 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.

Add below Maven dependencies to your Spring Boot project:
		<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

Let's first create a database in MySQL server using the below command:
create database springtest
Since we’re using MySQL as our database, we need to configure the database URLusername, and password so that Spring can establish a connection with the database on startup. Open the src/main/resources/application.properties file and add the following properties to it:
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 

In this step, we will create JwtUser, RefreshToken and Role 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

Create a security package in your Spring boot project and add the following JWT-related classes.

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

Let's create a Utility class named JwtUtils which provides methods for generating, validating, and extracting information from JSON Web Tokens (JWTs) used for authentication in a Spring Boot application.
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);
        }
    }

}
JwtAuthenticationFilter

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 extends BasicAuthenticationFilter, which is a class provided by Spring Security to handle basic authentication filtering.

  • The class has a constructor that takes an AuthenticationManager object, a JwtUserDetailsService 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's Authorization header, verifies and decodes the token using the provided secret, retrieves the email from the token, and loads the user details from the JwtUserDetailsService. Finally, it sets the authentication in the SecurityContextHolder 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 the JwtUserDetailsService and creates an UsernamePasswordAuthenticationToken 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.


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);
    }

}

This code defines a REST API endpoint for user refresh token. To login  POST request at the "/login" URL with the login credentials in the request body as a JSON object. 


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;
}

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);
        }
    }

}

Run & Test

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

Hibernate will automatically create the database tables so you don't need to create the tables manually.
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/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

We are what we repeatedly do. Excellence then, is not an act, but a habit.”

May 26, 2023

0
0

Comments

+

© 2024 Inc. All rights reserved. mulikevs