securing-apis-with-oauth-20-and-jwt-in-a-spring-boot-application.html

Securing APIs with OAuth 2.0 and JWT in a Spring Boot Application

In today's digital landscape, securing APIs is paramount. As developers, we must ensure that our applications are resilient against unauthorized access and data breaches. This is where OAuth 2.0 and JSON Web Tokens (JWT) come into play. In this article, we'll explore how to secure your APIs using these technologies within a Spring Boot application. We'll cover definitions, use cases, and provide actionable insights with code examples to help you implement secure API access effectively.

What is OAuth 2.0?

OAuth 2.0 is an open standard for access delegation commonly used for token-based authentication and authorization. It enables applications to obtain limited access to user accounts on HTTP services, such as Facebook, GitHub, or Google. By using OAuth 2.0, we can allow third-party applications to access user data without exposing user credentials.

Key Concepts of OAuth 2.0

  • Client: The application requesting access to a user's resources.
  • Resource Owner: The user who owns the data.
  • Authorization Server: The server that authenticates the user and issues access tokens.
  • Resource Server: The server that hosts the protected resources.

What is JWT?

JSON Web Tokens (JWT) are an open standard for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs are commonly used in authentication and authorization processes, providing a compact and self-contained way to transmit information.

Structure of a JWT

A JWT consists of three parts, separated by dots (.):

  1. Header: Contains metadata about the token, including the signing algorithm.
  2. Payload: Contains the claims, which are the statements about the user and additional data.
  3. Signature: Ensures that the token hasn't been altered.

Use Cases for OAuth 2.0 and JWT

  • Single Sign-On (SSO): Allowing users to authenticate once and gain access to multiple applications.
  • Mobile Applications: Providing secure access to APIs from mobile devices.
  • Third-Party Integrations: Enabling external applications to interact with your API without sharing user credentials.

Implementing OAuth 2.0 and JWT in a Spring Boot Application

Step 1: Setting Up Your Spring Boot Project

Create a new Spring Boot project using Spring Initializr with the following dependencies:

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

Step 2: Configure Spring Security

In your application.properties, configure the basic settings for Spring Security:

spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update

Step 3: Define the Security Configuration

Create a security configuration class to manage the OAuth 2.0 setup:

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;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;

@Configuration
@EnableWebSecurity
@EnableResourceServer
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/api/public/**").permitAll()  // Public endpoints
            .antMatchers("/api/private/**").authenticated() // Protected endpoints
            .and()
            .oauth2ResourceServer()
            .jwt(); // Enable JWT
    }
}

Step 4: Create a JWT Utility Class

Create a utility class to generate and validate JWT tokens:

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"; // Change this to a secure key

    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: Implementing the API Controller

Create a simple REST controller to demonstrate the secured API:

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/hello")
    public String publicHello() {
        return "Hello, this is a public endpoint!";
    }

    @GetMapping("/private/hello")
    public String privateHello() {
        return "Hello, this is a secured endpoint!";
    }
}

Step 6: Testing the API

Run your Spring Boot application and test the endpoints using Postman or cURL. Make sure to request an OAuth 2.0 token to access the secured endpoint.

Conclusion

Securing APIs with OAuth 2.0 and JWT in a Spring Boot application is a robust approach to maintaining user authentication and authorization. By following the steps outlined in this article, you can implement a secure API that protects sensitive data while providing seamless access to authorized users. As you develop your application, always remember to keep security at the forefront of your design and implementation strategies. Happy coding!

SR
Syed
Rizwan

About the Author

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