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

Hello! In this blog post, we will explain how to develop a backend service using Spring Boot and implement login and logout functions using JSON Web Token (JWT). JWT is a widely used method for transmitting and validating authentication information in web applications. Through this tutorial, we will explore the concept of JWT in detail and its implementation.

Table of Contents

  1. 1. JWT Concept
  2. 2. Spring Boot Project Setup
  3. 3. Entity Configuration
  4. 4. JWT Creation and Validation
  5. 5. Login Function Implementation
  6. 6. Logout Function Implementation
  7. 7. Comprehensive Test
  8. 8. Conclusion

1. JWT Concept

JWT (JSON Web Token) is a representative method for securely transmitting authentication information between two parties. JWT consists of three parts:

  • Header: Contains the type of token (JWT) and algorithm information.
  • Payload: Includes user information and other claims.
  • Signature: A signature created based on the Header and Payload, ensuring integrity.

The main advantage of JWT is that it allows information to be maintained on the client side, eliminating the need for the server to manage state. This is particularly useful in distributed systems or microservices architectures.

2. Spring Boot Project Setup

Let’s start by creating a simple RESTful API using Spring Boot. We will manage libraries using Maven.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>jwt-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>jwt-demo</name>
    <description>JWT Demo Project</description>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>2.6.6</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

After setting up the necessary dependencies as shown above, create the project directory and write the application class.

src/main/java/com/example/jwtdemo/JwtDemoApplication.java

package com.example.jwtdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JwtDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(JwtDemoApplication.class, args);
    }
}

3. Entity Configuration

To manage users, we will configure a User entity. This entity is needed to store user information.

src/main/java/com/example/jwtdemo/model/User.java

package com.example.jwtdemo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;

    // Getters and setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

4. JWT Creation and Validation

Now, let’s write a utility class to create and validate JWTs. This class will include methods to create and validate JWT tokens.

src/main/java/com/example/jwtdemo/util/JwtUtil.java

package com.example.jwtdemo.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

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

@Component
public class JwtUtil {
    private final String SECRET_KEY = "secret"; // Secret key
    private final int EXPIRATION_TIME = 1000 * 60 * 60; // 1 hour

    // Generate JWT
    public String generateToken(String username) {
        Map claims = new HashMap<>();
        return createToken(claims, username);
    }

    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_TIME))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    // Validate JWT
    public boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

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

    private Date extractExpiration(String token) {
        return extractAllClaims(token).getExpiration();
    }

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

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

5. Login Function Implementation

Now we will implement the login function. If the user provides valid credentials, we will generate and return a JWT.

src/main/java/com/example/jwtdemo/controller/AuthController.java

package com.example.jwtdemo.controller;

import com.example.jwtdemo.model.User;
import com.example.jwtdemo.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public Map login(@RequestBody User user) {
        // This part requires logic to check user information in the database.
        if ("test".equals(user.getUsername()) && "password".equals(user.getPassword())) {
            String token = jwtUtil.generateToken(user.getUsername());
            Map response = new HashMap<>();
            response.put("token", token);
            return response;
        } else {
            throw new RuntimeException("Invalid credentials");
        }
    }
}

6. Logout Function Implementation

Logout is typically performed by deleting or invalidating the JWT on the client side. Generally, logout is handled on the client side.

Here is an example of how to remove the JWT on the client:


localStorage.removeItem('token');

Since the server does not manage user state, there is no need for a separate logout endpoint on the server.

7. Comprehensive Test

Now that all implementations are complete, you can test the API using Postman or CURL.

  • Login Request: POST http://localhost:8080/auth/login – Send user information in JSON format in the Body.

{
    "username": "test",
    "password": "password"
}
response

{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

You can use the received JWT to make other API calls by adding it to the Authorization header as Bearer.

8. Conclusion

In this tutorial, we learned how to implement login and logout functions using JWT with Spring Boot. JWT is a lightweight authentication mechanism that can be effectively applied in various situations. Using JWT in practice can enhance security through efficient authentication and authorization management. We recommend experiencing various features based on JWT in the future.

Thank you! Questions and feedback are welcome in the comments below.