Your Search Bar For Shrewd Tips

How To Add Jwt In Spring Boot


How To Add JWT In Spring Boot

In today's modern web development, securing your APIs is crucial to protect sensitive data and ensure that only authorized users can access certain resources. JSON Web Tokens (JWT) have become a popular method for implementing stateless authentication in applications, especially with frameworks like Spring Boot. This comprehensive guide will walk you through the process of adding JWT authentication to your Spring Boot application, providing you with a solid foundation to enhance your application's security.

Understanding JWT and Its Role in Spring Boot

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. These claims are digitally signed, ensuring data integrity and authenticity. JWTs are commonly used for authentication and authorization in web applications because they are stateless, scalable, and easy to implement.

In a typical Spring Boot application, JWT can be used to authenticate users by issuing a token upon login, which is then sent with each subsequent request. The server verifies the token's validity and grants access accordingly. This approach eliminates the need for server-side session storage, making your application more scalable and easier to maintain.

Prerequisites for Implementing JWT in Spring Boot

  • Basic knowledge of Spring Boot and Java
  • Spring Security dependency added to your project
  • Understanding of REST API principles
  • JSON Web Token (JWT) library, such as io.jsonwebtoken (jjwt)

Ensure your development environment is set up with Java 8 or higher, and you are familiar with building REST APIs using Spring Boot.

Step-by-Step Guide to Adding JWT in Spring Boot

1. Add Dependencies

Start by including the necessary dependencies in your pom.xml if you're using Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <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>
</dependencies>

Adjust versions as needed, and if you're using Gradle, add equivalent dependencies to your build.gradle.

2. Configure UserDetailsService and AuthenticationManager

Spring Security requires a way to load user-specific data. Implement a UserDetailsService that retrieves user details from your data source (database, in-memory, etc.). For simplicity, here's an example with in-memory users:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER");
    }

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

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

This configuration sets up a simple in-memory user store. For production, you should implement UserDetailsService to fetch users from a database.

3. Create a JWT Utility Class

This class will handle token creation and validation. Here's an example implementation:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secretKey;

    @Value("${jwt.expirationMs}")
    private long expirationMs;

    public String generateToken(org.springframework.security.core.userdetails.UserDetails userDetails) {
        return Jwts.builder()
            .setSubject(userDetails.getUsername())
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + expirationMs))
            .signWith(SignatureAlgorithm.HS256, secretKey)
            .compact();
    }

    public String extractUsername(String token) {
        return extractClaims(token).getSubject();
    }

    public boolean validateToken(String token, org.springframework.security.core.userdetails.UserDetails userDetails) {
        final String username = extractUsername(token);
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
    }

    private boolean isTokenExpired(String token) {
        return extractClaims(token).getExpiration().before(new Date());
    }

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

Remember to define jwt.secret and jwt.expirationMs in your application.properties.

4. Create a Filter to Intercept Requests and Validate JWT

This filter will inspect incoming requests for a JWT token and validate it before passing the request along:

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.core.userdetails.UserDetailsService;
import org.springframework.web.filter.OncePerRequestFilter;

public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        final String authorizationHeader = request.getHeader("Authorization");
        String username = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
            jwt = authorizationHeader.substring(7);
            username = jwtUtil.extractUsername(jwt);
        }

        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authToken);
            }
        }
        chain.doFilter(request, response);
    }
}

5. Configure Security to Use the JWT Filter

Register the filter within your security configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtRequestFilter jwtRequestFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
                .antMatchers("/authenticate").permitAll()
                .anyRequest().authenticated()
            .and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

6. Create Authentication Controller to Issue JWT

Implement an endpoint that authenticates user credentials and returns a JWT token:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.*;

@RestController
public class AuthenticationController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/authenticate")
    public String createAuthenticationToken(@RequestBody AuthenticationRequest authRequest) throws Exception {
        try {
            authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(authRequest.getUsername(), authRequest.getPassword())
            );
        } catch (AuthenticationException e) {
            throw new Exception("Incorrect username or password", e);
        }

        final UserDetails userDetails = 
            new org.springframework.security.core.userdetails.User(authRequest.getUsername(), authRequest.getPassword(), new ArrayList<>());

        final String jwt = jwtUtil.generateToken(userDetails);
        return jwt;
    }
}

class AuthenticationRequest {
    private String username;
    private String password;

    // getters and setters
}

7. Testing Your JWT-secured API

Once everything is configured, you can test your API as follows:

  • Make a POST request to /authenticate with JSON body containing username and password.
  • Receive a JWT token in response.
  • Include the token in the Authorization header of subsequent API requests using the Bearer schema:
Authorization: Bearer your-jwt-token-here

If the token is valid and not expired, your protected endpoints will grant access. Otherwise, you'll receive an unauthorized response.

Conclusion

Adding JWT authentication to your Spring Boot application enhances security by enabling stateless, scalable, and secure communication between clients and servers. By following this step-by-step guide, you now have the knowledge to implement JWT in your own projects, ensuring that only authenticated users can access sensitive resources. Remember to handle token expiration, refresh tokens, and secure your secret keys to further strengthen your application's security posture.

Implementing JWT is a powerful way to modernize your application's authentication mechanism. Keep exploring additional features such as token revocation, multi-factor authentication, and integrating with OAuth providers to build even more robust security solutions.


Disclaimer: Articles are written by Humans, AI or Both. Verify Important information.

Shrewdnia

Shrewdnia

Shrewdnia is a destination for curious minds seeking clarity, knowledge, and informed perspectives. Through insightful articles and practical guides our passionate team explores a wide range of topics designed to help readers understand the world around them, make smarter decisions, and stay informed in an ever-changing landscape.


💡 Every question sparks discovery, and every perspective enriches the conversation. Share your thoughts and insights in the comments 👇

Back to blog

Leave a comment

JOIN THE SHREWDNIA COMMUNITY FORUM

What do you think?

Have an opinion, experience, or question about this topic? Join the Shrewdnia Forum and share your thoughts with other readers.

Join the Forum →