How to Implement JWT In Spring Boot?

23 minutes read

In order to implement JWT (JSON Web Token) in a Spring Boot application, you need to follow these steps:

  1. Add the necessary dependencies: Include the required dependencies in your Spring Boot project's pom.xml file. These dependencies typically include spring-boot-starter-security and jjwt (Java JWT library).
  2. Configure Spring Security: Modify your application's security configuration to enable JWT authentication. Create a class that extends WebSecurityConfigurerAdapter and overrides the configure(HttpSecurity http) method. Inside this method, you can specify security rules, such as which endpoints require authentication and which should be excluded. You can also configure the filters for JWT authentication.
  3. Create a JWT utility class: Implement a utility class to handle the creation, validation, and parsing of JWT tokens. This class usually contains methods to generate a token, validate a token, and extract user information from the token.
  4. Implement user authentication: Define a user class that implements the UserDetails interface provided by Spring Security. This class represents the authenticated user and typically contains information such as username, password, and roles. You can also create a user service class to load user details from a database or any other source.
  5. Generate JWT tokens: When a user successfully logs in, generate a JWT token using the utility class defined earlier. The token should include relevant user information as claims, such as username and roles. Add this token as part of the authentication response.
  6. Secure endpoints using JWT: Configure your Spring Boot application to secure endpoints using JWT. Within your controller classes or methods, annotate the endpoints that require authentication with @PreAuthorize or any other relevant annotations. These annotations control access to specific endpoints based on the presence, validity, or role claims of the JWT token.
  7. Validate and extract user information from JWT tokens: Implement logic to validate each incoming request's JWT token. Retrieve user information from the token, such as username and roles, and use it to control access, perform authorization checks, or display personalized content.


Remember that this is just a high-level overview of the necessary steps for implementing JWT in a Spring Boot application. Details, such as key generation and management, token expiration, and token refresh, may need to be considered depending on your application's specific requirements.

Best Spring Boot Books to Read in May 2024

1
Full Stack Development with Spring Boot and React: Build modern and scalable web applications using the power of Java and React, 3rd Edition

Rating is 5 out of 5

Full Stack Development with Spring Boot and React: Build modern and scalable web applications using the power of Java and React, 3rd Edition

2
Spring Boot Persistence Best Practices: Optimize Java Persistence Performance in Spring Boot Applications

Rating is 4.9 out of 5

Spring Boot Persistence Best Practices: Optimize Java Persistence Performance in Spring Boot Applications

3
Spring Boot in Action

Rating is 4.8 out of 5

Spring Boot in Action

4
Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications

Rating is 4.7 out of 5

Spring Boot: Up and Running: Building Cloud Native Java and Kotlin Applications

5
Learning Spring Boot 3.0: Simplify the development of production-grade applications using Java and Spring, 3rd Edition

Rating is 4.6 out of 5

Learning Spring Boot 3.0: Simplify the development of production-grade applications using Java and Spring, 3rd Edition

6
Spring in Action, Sixth Edition

Rating is 4.5 out of 5

Spring in Action, Sixth Edition

7
Modern API Development with Spring and Spring Boot: Design highly scalable and maintainable APIs with REST, gRPC, GraphQL, and the reactive paradigm

Rating is 4.4 out of 5

Modern API Development with Spring and Spring Boot: Design highly scalable and maintainable APIs with REST, gRPC, GraphQL, and the reactive paradigm

8
Spring Boot and Angular: Hands-on full stack web development with Java, Spring, and Angular

Rating is 4.3 out of 5

Spring Boot and Angular: Hands-on full stack web development with Java, Spring, and Angular


How can I generate JWT tokens in Spring Boot?

To generate JWT tokens in a Spring Boot application, you can follow these steps:

  1. Add the required dependencies: spring-boot-starter-web for building RESTful web services jjwt for handling JWT
  2. Create a custom class, let's say JwtUtil, to handle JWT token generation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {
    private final Key key;

    public JwtUtil() {
        // Generate a secure key using a String passphrase
        byte[] encodedKey = "my-secret-key".getBytes(StandardCharsets.UTF_8);
        this.key = Keys.hmacShaKeyFor(encodedKey);
    }

    public String generateToken(String username) {
        // Define the claims for the JWT token
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", username);
        claims.put("created", new Date());
        
        // Generate the JWT token
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + 86400000))  // Set the token expiration time
                .signWith(key)
                .compact();
    }

    public String extractUsername(String token) {
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody();

        return claims.getSubject();
    }
}


  1. Create a REST controller to expose an endpoint for token generation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JwtController {
    private final JwtUtil jwtUtil;

    @Autowired
    public JwtController(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
    }

    @GetMapping("/generate-token/{username}")
    public String generateToken(@PathVariable String username) {
        return jwtUtil.generateToken(username);
    }
}


  1. Run the Spring Boot application and access the /generate-token/{username} endpoint with a username as a path variable. It will return the generated JWT token.


Note: Remember to handle token verification and authentication using the same key in a real-world scenario.


How can I handle JWT authentication and authorization in my Spring Boot controllers?

To handle JWT authentication and authorization in your Spring Boot controllers, you can follow the steps below:

  1. Add the necessary dependencies in your pom.xml file: org.springframework.bootspring-boot-starter-security io.jsonwebtokenjjwt-api0.11.2io.jsonwebtokenjjwt-impl0.11.2runtimeio.jsonwebtokenjjwt-jackson0.11.2runtime
  2. Create a JwtUtil class to handle JWT-related operations. This class will be responsible for generating and parsing JWT tokens. import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @Component public class JwtUtil { @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private long expiration; public String generateToken(UserDetails userDetails) { Map claims = new HashMap<>(); return createToken(claims, userDetails.getUsername()); } private String createToken(Map claims, String subject) { return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + expiration)) .signWith(SignatureAlgorithm.HS256, secret) .compact(); } public Boolean validateToken(String token, UserDetails userDetails) { final String username = extractUsername(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public Boolean isTokenExpired(String token) { return extractClaim(token, Claims::getExpiration).before(new Date()); } public T extractClaim(String token, Function claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } private Claims extractAllClaims(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } }
  3. Create a JwtRequest class to represent the JWT authentication request payload. public class JwtRequest { private String username; private String password; // getters and setters // ... }
  4. Create a JwtResponse class to represent the JWT authentication response payload. public class JwtResponse { private String accessToken; public JwtResponse(String accessToken) { this.accessToken = accessToken; } public String getAccessToken() { return accessToken; } // getters and setters // ... }
  5. Create a JwtAuthenticationController class with an endpoint for JWT authentication. import com.example.model.JwtRequest; import com.example.model.JwtResponse; import com.example.service.JwtUserDetailsService; import com.example.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.AuthenticationException; import org.springframework.web.bind.annotation.*; @RestController @CrossOrigin public class JwtAuthenticationController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtUtil jwtUtil; @Autowired private JwtUserDetailsService userDetailsService; @RequestMapping(value = "/authenticate", method = RequestMethod.POST) public ResponseEntity createAuthenticationToken(@RequestBody JwtRequest authenticationRequest) throws Exception { authenticate(authenticationRequest.getUsername(), authenticationRequest.getPassword()); final UserDetails userDetails = userDetailsService .loadUserByUsername(authenticationRequest.getUsername()); final String token = jwtUtil.generateToken(userDetails); return ResponseEntity.ok(new JwtResponse(token)); } private void authenticate(String username, String password) throws AuthenticationException { try { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password)); } catch (DisabledException e) { throw new Exception("USER_DISABLED", e); } catch (BadCredentialsException e) { throw new Exception("INVALID_CREDENTIALS", e); } } }
  6. Configure Spring Security by creating a WebSecurityConfig class that extends WebSecurityConfigurerAdapter. This class will handle authentication and authorization based on JWT tokens. import com.example.filter.JwtRequestFilter; import com.example.service.JwtUserDetailsService; 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.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) // enable method level security annotations public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private JwtUserDetailsService jwtUserDetailsService; @Autowired private JwtRequestFilter jwtRequestFilter; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(jwtUserDetailsService); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable() .authorizeRequests().antMatchers("/authenticate", "/register").permitAll() // Allow access to authentication and registration endpoints .anyRequest().authenticated() // Require authentication for all other endpoints .and().exceptionHandling().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); // Make the application stateless httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); // Add the JwtRequestFilter } }
  7. Create your controllers and use the @PreAuthorize annotation to specify the roles or authorities required to access the endpoints. import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api") public class ApiController { @GetMapping("/public") public String publicEndpoint() { return "This is a public endpoint"; } @GetMapping("/private") @PreAuthorize("hasRole('ROLE_USER')") // Only users with the 'ROLE_USER' authority can access this endpoint public String privateEndpoint() { return "This is a private endpoint"; } }


With these steps, you have implemented JWT token-based authentication and authorization in your Spring Boot controllers. The JwtAuthenticationController handles the generation of the JWT token upon successful authentication, and the WebSecurityConfig class enables the necessary security configurations for JWT authentication and authorization. Finally, you can use the @PreAuthorize annotation in your controllers to specify the required roles or authorities for accessing specific endpoints.


How can I secure WebSocket communication with JWT in Spring Boot?

To secure WebSocket communication with JWT in Spring Boot, you can follow these steps:

  1. Add the necessary dependencies to your project's build file. In your pom.xml file, add the following dependencies:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

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


  1. Create a JwtTokenProvider class to generate and validate JWT tokens. This class will contain methods to generate a token, get the user details from a token, and validate a token. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtTokenProvider {

    private static final String SECRET_KEY = "your-secret-key";
    private static final long EXPIRATION_TIME = 86400000; // 1 day

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

    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    public boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    private boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    private Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    private String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    private <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

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


  1. Create a WebSocketConfig class to configure the WebSocket endpoint and message broker registry. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app")
                .enableSimpleBroker("/topic");
    }
}


  1. Create a WebSocketAuthInterceptor class to intercept the WebSocket handshake and validate the JWT token. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
public class WebSocketAuthInterceptor extends ChannelInterceptorAdapter {

    private static final String AUTHORIZATION_HEADER = "Authorization";
    private static final String TOKEN_PREFIX = "Bearer ";

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);

        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            String authorizationHeader = accessor.getFirstNativeHeader(AUTHORIZATION_HEADER);
            
            if (StringUtils.hasText(authorizationHeader) && authorizationHeader.startsWith(TOKEN_PREFIX)) {
                String jwtToken = authorizationHeader.substring(TOKEN_PREFIX.length());
                if (jwtTokenProvider.validateToken(jwtToken)) {
                    UsernamePasswordAuthenticationToken authentication = getAuthentication(jwtToken);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    accessor.setUser(authentication);
                }
            }
        }
        return message;
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String token) {
        // Extract the username from the token and create an Authentication object
        // You can query your user details service here to get the user details
        String username = jwtTokenProvider.getUsernameFromToken(token);
        return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
    }
}


  1. Update your SecurityConfig class to include a configuration for WebSocket request handling and authentication. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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.authorization.builders.HttpSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

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

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

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/api/auth/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .apply(new JwtConfigurer(jwtTokenProvider));
    }
}


  1. Create a JwtConfigurer class to configure JWT authentication filter. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

public class JwtConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

    private JwtTokenProvider jwtTokenProvider;

    public JwtConfigurer(JwtTokenProvider jwtTokenProvider) {
        this.jwtTokenProvider = jwtTokenProvider;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        JwtTokenFilter customFilter = new JwtTokenFilter(jwtTokenProvider);
        http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
    }
}


  1. Create a JwtTokenFilter class to intercept requests and validate the JWT token. Here's an example implementation:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.ExpiredJwtException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtTokenFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
            throws ServletException, IOException {
        String token = getToken(request);

        try {
            if (token != null && jwtTokenProvider.validateToken(token)) {
                String username = jwtTokenProvider.getUsernameFromToken(token);
                UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (ExpiredJwtException e) {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token expired");
            return;
        }

        filterChain.doFilter(request, response);
    }

    private String getToken(HttpServletRequest request) {
        String authorizationHeader = request.getHeader("Authorization");

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            return authorizationHeader.substring(7);
        }

        return null;
    }
}


Now your WebSocket communication in Spring Boot is secured with JWT authentication. Clients should include the JWT token in the Authorization header with the value Bearer <token> to establish a WebSocket connection.

Best Cloud Providers to Host Java Spring Boot in 2024

1
AWS

Rating is 5 out of 5

AWS

2
DigitalOcean

Rating is 4.9 out of 5

DigitalOcean

3
Vultr

Rating is 4.8 out of 5

Vultr

4
Cloudways

Rating is 4.7 out of 5

Cloudways


How can I implement password reset functionality with JWT in Spring Boot?

To implement password reset functionality with JWT in a Spring Boot application, you can follow the steps outlined below:

  1. User Requests Password Reset: When a user wants to reset their password, they can make a request to a specified endpoint (e.g., /api/reset-password) with their email address.
  2. Generate Reset Token: Generate a unique reset token for the user, which will be embedded in a JWT. The token should have a short expiration time to ensure security.
  3. Store Reset Token: Save the reset token along with the user's email address and an expiry timestamp in a database or any other persistent storage.
  4. Send Reset Email: Send an email to the user containing a link that includes the reset token as a parameter, such as http://example.com/reset-password?token={reset_token}. This link should direct the user to a password reset page in your application.
  5. Reset Password Page: Create a password reset page that accepts the reset token as a request parameter and displays a form to enter a new password.
  6. Verify Reset Token: When the user submits the form with a new password, your backend should validate the reset token. Ensure that it has not expired and matches the one associated with the user's email address.
  7. Update Password: If the reset token is valid, update the user's password with the new one provided by the user.


Here's a basic implementation example in Spring Boot:

  1. Create a ResetToken entity to store the reset token details in the database.
  2. Implement a ResetTokenRepository to handle the CRUD operations for the ResetToken entity.
  3. Build an API endpoint to receive a reset password request, generate a reset token, store it in the database, and send an email to the user with the reset link.
  4. Create a password reset page and implement an API endpoint to handle the form submission. Verify the reset token, check its expiration, and update the user's password if everything is valid.


Make sure to include proper exception handling, security measures, and input validation to ensure a secure implementation.


Remember, this is a basic outline, and the implementation may vary depending on your specific requirements and architecture.


How can I secure my Spring Boot application against JWT token tampering and forgery?

Here are some suggestions to secure your Spring Boot application against JWT token tampering and forgery:

  1. Use a strong JWT secret: Ensure that you use a long and randomly generated secret key to sign and verify your JWT tokens. This makes it difficult for attackers to guess or brute force the secret.
  2. Validate token signatures: Always validate the signature of incoming JWT tokens to ensure they have not been tampered with. Use a JWT library with built-in signature verification capabilities.
  3. Avoid storing sensitive data in the token: Do not include sensitive information such as passwords or credit card numbers in the JWT token. Instead, store such data securely on the server-side and only include a reference or identifier in the token.
  4. Include expiration time: Set a reasonably short expiration time for your JWT tokens. This ensures that even if a token is compromised, it will be valid for a limited period, reducing the risk of unauthorized access.
  5. Implement token refresh mechanism: Use a refresh token mechanism to allow users to obtain new valid JWT tokens without re-authenticating frequently. This reduces the window of opportunity for attackers to exploit compromised tokens.
  6. Implement token revocation and invalidation: Provide mechanisms to invalidate or revoke issued JWT tokens. This can be done by maintaining a blacklist or revocation list on the server-side and checking token validity against it.
  7. Use HTTPS for communication: Ensure that your application uses HTTPS for all communication to encrypt data in transit. This helps protect your JWT tokens from being intercepted or modified by malicious actors.
  8. Implement proper access control: Define and enforce proper access control rules within your application. Only allow authenticated and authorized users to access specific resources or perform certain actions.
  9. Employ rate-limiting and intrusion detection: Implement rate-limiting mechanisms and intrusion detection systems to detect and prevent brute-force attacks or excessive access attempts that could compromise JWT tokens.
  10. Regularly update dependencies and libraries: Keep your dependencies and libraries up-to-date to ensure you have the latest security patches and bug fixes, reducing the risk of vulnerabilities that could be exploited by attackers.


How can I validate and decode JWT tokens in Spring Boot?

To validate and decode JWT tokens in Spring Boot, you can use the following steps:

  1. Add the necessary dependencies to your pom.xml file:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>


  1. Create a configuration class to define the JWT secret key and its signing algorithm:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Configuration
public class JwtConfig {
    @Value("${jwt.secret}")
    private String secretKey;

    @Bean
    public JwtParser jwtParser() {
        return Jwts.parser().setSigningKey(secretKey);
    }
}


  1. Create a JwtTokenUtil class that provides methods for validating and decoding JWT tokens:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Component
public class JwtTokenUtil {
    @Autowired
    private JwtParser jwtParser;

    public Jws<Claims> validateToken(String token) {
        return jwtParser.parseClaimsJws(token);
    }

    public String getUsernameFromToken(String token) {
        return validateToken(token).getBody().getSubject();
    }
}


  1. Use the JwtTokenUtil in your controller or service to validate and decode the JWT token:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@RestController
public class UserController {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest loginRequest) {
        // Authenticate user and generate JWT token...
        return generateToken(username);
    }

    @GetMapping("/user")
    public String getUser(@RequestHeader("Authorization") String authorizationHeader) {
        String token = authorizationHeader.substring(7);
        String username = jwtTokenUtil.getUsernameFromToken(token);
        
        // Return user details...
    }
}


Make sure to replace the placeholders in the code with your own implementation logic and secret key configuration.


How can I enable CORS (Cross-Origin Resource Sharing) for JWT authentication in Spring Boot?

To enable CORS for JWT authentication in Spring Boot, you can follow these steps:

  1. Add the @CrossOrigin annotation to your Spring Controller class or specific request handling method. This will enable cross-origin requests from the specified origin(s).
1
2
3
4
5
@RestController
@CrossOrigin(origins = "http://localhost:3000") // Replace with your frontend origin
public class MyController {
    // Controller methods
}


  1. Alternatively, you can configure global CORS settings in your Spring Boot application by creating a WebMvcConfigurer bean. Create a class that implements the WebMvcConfigurer interface and override the addCorsMappings method.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000") // Replace with your frontend origin
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}


  1. Configure CORS for JWT authentication-specific endpoints. If you have specific endpoints for JWT authentication (e.g., login or token refresh), you can specify CORS settings for those endpoints.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .authorizeRequests()
                .antMatchers("/api/auth/login").permitAll()
                .antMatchers("/api/auth/refresh").permitAll()
                .anyRequest().authenticated();
    }
}


With the above configurations, CORS will be enabled for JWT authentication in your Spring Boot application, allowing cross-origin requests from the specified origins or globally.

Facebook Twitter LinkedIn Telegram Whatsapp Pocket

Related Posts:

To integrate Spring Boot with Angular, the following steps can be followed:Create a new Spring Boot project: Start by setting up a new Spring Boot project using your preferred IDE or Spring Initializer. Include the necessary dependencies for web and data. Set ...
To connect Spring Boot to MySQL, you need to follow these steps:First, make sure you have MySQL installed and running on your system. In your Spring Boot project, open the application.properties file. Add the following properties to the file: spring.datasourc...
To stop a Spring Boot application from the command line, you need to perform the following steps:Identify the process ID (PID) of the running Spring Boot application. You can do this by using the jps command. Open the command prompt and type jps -l. Look for t...