Spring Boot 3.4 provides a powerful and flexible way to intercept and secure HTTP requests before they reach your application logic. In modern web applications, having the ability to inspect, validate, and authenticate incoming requests is essential — whether for enforcing authentication, logging, or monitoring. In this post, we’ll create a complete, runnable Spring Boot 3.4 project that shows how to setup a WebRequest Filter in Spring Boot 3.4 to intercept every incoming request and validate security credentials before allowing access.
What We’ll Build
We’ll create a small but complete Spring Boot application that:
- Exposes a public endpoint (
/public
) accessible by anyone - Exposes a protected endpoint (
/secure
) accessible only with a valid API key - Uses a custom WebRequest filter to intercept and validate every request
- Responds with
401 Unauthorized
when credentials are missing or invalid
By the end, you’ll have a runnable demo that illustrates how Spring Boot filters work — and how to use them to implement lightweight authentication mechanisms.
Background: Understanding Spring Security and Filters
Spring Security is a powerful and highly customizable framework within the Spring ecosystem designed to handle authentication, authorization, and security enforcement for Java applications. It provides the foundation for building secure APIs and web applications by managing how users and systems access resources.
At its core, Spring Security uses a chain of filters that intercept each web request before it reaches your application’s controllers. Each filter has a specific role — such as validating a JWT token, checking user sessions, enforcing CSRF protection, or handling login forms. This filter-based architecture allows developers to insert custom filters anywhere in the chain to implement custom logic like logging, auditing, or header validation.
Key components of Spring Security include:
- AuthenticationManager – Handles authentication logic and user validation.
- SecurityFilterChain – Defines how filters are applied to incoming requests.
- UserDetailsService – Loads user-specific data from a database or service.
- PasswordEncoder – Hashes and validates passwords (e.g., BCrypt).
- GrantedAuthority / Roles – Defines what each authenticated user is allowed to do.
In this example, we’ll focus on the filter mechanism, showing how to create a custom filter using OncePerRequestFilter
— one of the core components used internally by Spring Security itself.
WebRequest Filter in Spring Boot 3.4 – Project Setup
Dependencies:
- Spring Boot 3.4.x
- Spring Web
- (Optional) Spring Boot Starter Test
Create a new Spring Boot Maven project using Spring Initializr or manually with the following dependencies:
Project: Maven
Language: Java
Spring Boot: 3.4.0
Dependencies: Spring Web
Directory Structure
webrequest-filter-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/filterdemo/
│ │ │ ├── FilterDemoApplication.java
│ │ │ ├── filters/
│ │ │ │ └── ApiKeyAuthFilter.java
│ │ │ └── controllers/
│ │ │ └── DemoController.java
│ │ └── resources/
│ │ └── application.yml
└── pom.xml
Step 1: pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>filterdemo</artifactId>
<version>1.0.0</version>
<name>WebRequest Filter Demo</name>
<properties>
<java.version>17</java.version>
<spring.boot.version>3.4.0</spring.boot.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- For testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
XMLStep 2: Application Entry Point
package com.example.filterdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FilterDemoApplication {
public static void main(String[] args) {
SpringApplication.run(FilterDemoApplication.class, args);
}
}
JavaStep 3: Implement a Custom Filter
We’ll use OncePerRequestFilter
from org.springframework.web.filter
— this ensures that your filter executes once per request, even if the request passes through multiple dispatch phases.
package com.example.filterdemo.filters;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class ApiKeyAuthFilter extends OncePerRequestFilter {
private static final String API_KEY_HEADER = "X-API-KEY";
private static final String EXPECTED_API_KEY = "my-secret-key";
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String apiKey = request.getHeader(API_KEY_HEADER);
// Allow public endpoints to bypass authentication
String path = request.getRequestURI();
if (path.startsWith("/public")) {
filterChain.doFilter(request, response);
return;
}
// Check API key for secure endpoints
if (apiKey == null || !EXPECTED_API_KEY.equals(apiKey)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("Unauthorized: Invalid or missing API key");
return;
}
// Continue with the next filter in the chain
filterChain.doFilter(request, response);
}
}
Java✅ Explanation:
- The filter runs for every HTTP request.
- Requests to
/public
skip authentication. - Requests to
/secure
must include the correctX-API-KEY
header. - Unauthorized requests are immediately rejected.
Step 4: Controller with Public and Secure Endpoints
package com.example.filterdemo.controllers;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/public")
public String publicEndpoint() {
return "✅ This is a public endpoint. No API key required.";
}
@GetMapping("/secure")
public String secureEndpoint() {
return "🔒 This is a secure endpoint. You provided a valid API key!";
}
}
JavaStep 5: Optional application.yml
server:
port: 8080
spring:
application:
name: webrequest-filter-demo
YAMLStep 6: Run and Test
Run:
mvn spring-boot:run
Test your endpoints:
Public Endpoint
curl http://localhost:8080/public
Response:
This is a public endpoint. No API key required.
Secure Endpoint (No Key)
curl http://localhost:8080/secure
Response:
Unauthorized: Invalid or missing API key
Secure Endpoint (With Key)
curl -H "X-API-KEY: my-secret-key" http://localhost:8080/secure
Response:
This is a secure endpoint. You provided a valid API key!
How It Works
Spring Boot automatically registers every Filter
bean in the application context.
The OncePerRequestFilter
ensures your logic executes exactly once per HTTP request.
When a request comes in:
- The
ApiKeyAuthFilter
runs first. - It validates the
X-API-KEY
header. - If the key is missing or invalid, the filter stops the chain and returns a
401
. - Otherwise, the request continues to the controller.
Next Steps
You can easily extend this filter to:
- Validate JWT tokens instead of static keys
- Integrate with Spring Security’s SecurityFilterChain
- Load keys or tokens from a database
- Apply different filters for different URL patterns
For configurable keys:
app:
api-key: my-secret-key
and inject it:
@Value("${app.api-key}")
private String expectedKey;
Conclusion
With Spring Boot 3.4, building custom request filters has never been simpler. Using OncePerRequestFilter
, you can intercept and secure all incoming requests in a clean, reusable, and testable way.
Combined with Spring Security’s powerful filter chain, this approach forms the foundation for building robust, secure, and scalable Java APIs.
You now have a complete working example demonstrating how to:
- Intercept every HTTP request
- Validate API credentials
- Control access to public and private endpoints
While you are here, maybe try one of my apps for the iPhone.
Snap! I was there on the App Store
Listed below are the links to the first two parts of this series
How to build a blog engine with React & Spring Boot – Part 1 – My Day To-Do (mydaytodo.com)
How to build a blog engine with React & Spring Boot – Part 2 – My Day To-Do (mydaytodo.com)
Here are some of my other bloposts,
How to unit test react-redux app – My Day To-Do (mydaytodo.com)
0 Comments