securing-rest-apis-with-jwt-authentication-in-a-spring-boot-application.html

Securing REST APIs with JWT Authentication in a Spring Boot Application

In today’s digital landscape, securing REST APIs is paramount. With the rise of mobile applications and microservices architecture, developers often need to ensure that their APIs are not just functional but also secure. One of the most effective methods for securing REST APIs is through the use of JSON Web Token (JWT) authentication. This article will guide you through the process of implementing JWT authentication in a Spring Boot application, providing detailed explanations, code snippets, and best practices.

What is JWT?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Key Components of JWT

A JWT consists of three parts:

  1. Header: Contains metadata about the token, typically including the type of token (JWT) and the signing algorithm being used (e.g., HMAC SHA256).

Example: json { "alg": "HS256", "typ": "JWT" }

  1. Payload: Contains the claims or the actual data. Claims can be registered, public, or private.

Example: json { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }

  1. Signature: To create the signature part, you take the encoded header, the encoded payload, a secret, and the algorithm specified in the header.

JWT Use Cases

  • Authentication: Once a user logs in, a JWT is returned. The client stores this token and sends it with every request, allowing the server to authenticate the user.
  • Information Exchange: JWTs can be used to securely exchange information between parties, ensuring integrity and authenticity.

Setting Up a Spring Boot Application

Before we dive into JWT implementation, let’s set up a basic Spring Boot application.

Step 1: Create a New Spring Boot Project

You can create a Spring Boot application using Spring Initializr. Choose the following dependencies:

  • Spring Web
  • Spring Security
  • Spring Data JPA
  • H2 Database (for testing)

Step 2: Project Structure

Your project structure should look like this:

src
 └── main
     ├── java
     │   └── com
     │       └── example
     │           └── jwtsecurity
     │               ├── JwtSecurityApplication.java
     │               ├── config
     │               │   └── SecurityConfig.java
     │               ├── controller
     │               │   └── AuthController.java
     │               ├── model
     │               │   └── User.java
     │               └── service
     │                   └── UserService.java
     └── resources
         └── application.properties

Step 3: Add Dependencies

In your pom.xml, make sure to include the necessary dependencies:

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

Implementing JWT Authentication

Step 1: Create the User Model

Create a simple User model that represents our user entity.

package com.example.jwtsecurity.model;

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

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

    // Getters and Setters
}

Step 2: Create the User Service

The UserService will handle user registration and retrieval.

package com.example.jwtsecurity.service;

import com.example.jwtsecurity.model.User;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserService {
    private final List<User> users = new ArrayList<>();

    public User save(User user) {
        users.add(user);
        return user;
    }

    public User findByUsername(String username) {
        return users.stream().filter(u -> u.getUsername().equals(username)).findFirst().orElse(null);
    }
}

Step 3: Configure Security

Create a SecurityConfig class to configure Spring Security for JWT authentication.

package com.example.jwtsecurity.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .authorizeRequests()
            .antMatchers("/auth/**").permitAll()
            .anyRequest().authenticated();
    }
}

Step 4: Create JWT Utility Class

This class will help in creating and validating JWTs.

package com.example.jwtsecurity.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 String SECRET_KEY = "secret";

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

    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() + 1000 * 60 * 60 * 10)) // 10 hours
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

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

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

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

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

Step 5: Create Authentication Controller

This controller will handle user authentication and provide the JWT.

package com.example.jwtsecurity.controller;

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

@RestController
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/register")
    public User register(@RequestBody User user) {
        return userService.save(user);
    }

    @PostMapping("/login")
    public String login(@RequestBody User user) {
        User existingUser = userService.findByUsername(user.getUsername());
        if (existingUser != null && existingUser.getPassword().equals(user.getPassword())) {
            return jwtUtil.generateToken(user.getUsername());
        }
        throw new RuntimeException("Invalid credentials");
    }
}

Step 6: Testing the Application

Run your Spring Boot application and use tools like Postman to test the /auth/register and /auth/login endpoints. Upon successful login, you will receive a JWT that can be used to authenticate subsequent requests.

Conclusion

Securing REST APIs with JWT authentication in a Spring Boot application is a powerful method to ensure that your application remains safe and secure. By following the steps outlined in this article, you can implement JWT authentication effectively. Remember to keep your secret keys secure and consider using HTTPS for enhanced security. As you build your applications, always stay informed about best practices in API security to keep your systems robust against potential threats.

SR
Syed
Rizwan

About the Author

Syed Rizwan is a Machine Learning Engineer with 5 years of experience in AI, IoT, and Industrial Automation.