Spring Boot Backend Development Course, Implementing Login and Logout with JWT, Implementing Token API

Implementing Login/Logout with JWT and Token API

Recently, the architecture of web applications has become increasingly complex, and security issues are a significant concern for all developers. In this course, we will take a detailed look at how to implement login and logout features based on JWT (JSON Web Token) and the token API using Spring Boot. This course is targeted at developers with basic Spring Boot development experience and includes an understanding of JWT.

Table of Contents

1. What is JWT?

JWT stands for JSON Web Token, an open standard (RFC 7519) for securely transmitting user authentication information. JWT is one of the most commonly used authentication methods, used to prove that a user is logged in without the need to maintain state between the client and server. JWT consists of three parts:

  • Header: Specifies the type of token and the signing algorithm.
  • Payload: Contains user information and claims.
  • Signature: A signature created based on the header and payload.

One of the main advantages of JWT is that it allows for stateless authentication. This means that the server does not store session information, thereby reducing the server’s burden and making it easier to scale out.

2. Project Setup

Before starting the project, you need to create a Spring Boot project. You can easily set up a project using Spring Initializr. Add the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database (or any database of your choice)
  • jjwt (Java JWT library)

After creating the project, add the necessary libraries to your `pom.xml`:



    
    
        io.jsonwebtoken
        jjwt
        0.9.1
    


3. User Authentication and JWT Issuance

To authenticate users, create a User entity and UserRepository. Then, set up the service layer and implement the logic to generate JWT.


// Example of User Entity
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String username;
    private String password;
    
    // getters and setters
}


// Example of UserRepository
public interface UserRepository extends JpaRepository {
    Optional findByUsername(String username);
}

Now, let’s add the functionality to create JWT:


// JwtUtil.java
@Component
public class JwtUtil {
    
    private String secretKey = "secret"; // In production, manage this in environment variables or separate files
    
    public String generateToken(String username) {
        return Jwts.builder()
                    .setSubject(username)
                    .setIssuedAt(new Date(System.currentTimeMillis()))
                    .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
                    .signWith(SignatureAlgorithm.HS256, secretKey)
                    .compact();
    }
}

3.1 Implementing Login API

Now we will implement a Controller to handle login requests:


// AuthController.java
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private JwtUtil jwtUtil;
    
    @Autowired
    private UserRepository userRepository;
    
    @PostMapping("/login")
    public ResponseEntity login(@RequestBody User user) {
        authenticate(user.getUsername(), user.getPassword());
        String token = jwtUtil.generateToken(user.getUsername());
        return ResponseEntity.ok(token);
    }
    
    private void authenticate(String username, String password) {
        Authentication authentication = authenticationManager.authenticate(
            new UsernamePasswordAuthenticationToken(username, password)
        );
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
}

4. Token Verification and Authorization

To handle authenticated requests using JWT, you need to implement a filter to validate the token in the request header.


// JwtRequestFilter.java
@Component
public class JwtRequestFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserDetailsService userDetailsService;

    @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 = userDetailsService.loadUserByUsername(username);
            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                        new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(request, response);
    }
}

5. Implementing Logout Functionality

Since JWT is stateless, implementing logout functionality means that the client simply deletes the token. However, it is also possible to implement logout functionality by managing a blacklist on the server.


// Example of Logout
@PostMapping("/logout")
public ResponseEntity logout(HttpServletRequest request) {
    String token = request.getHeader("Authorization").substring(7);
    // Implement logic to add to blacklist here
    return ResponseEntity.ok("Logout successful");
}

6. API Testing

You can test the API using tools like Postman. After the login request, confirm that you can access protected resources using the JWT issued by the server.

7. Conclusion

In this course, we learned how to implement a JWT-based authentication system using Spring Boot. Depending on the system requirements, JWT can be utilized in various ways, and security should always remain a key consideration. Going forward, consider adding more advanced features to expand the system.