This article focuses on four core interception components in the microservice request lifecycle: Gateway Filters, Servlet Filters, MVC Interceptors, and Feign Interceptors. It addresses common questions such as where authentication should live, how to propagate tokens, and which layer can access Spring Beans. Keywords: JWT authentication, token propagation, Spring Security.
The technical specification snapshot provides quick context
| Parameter | Description |
|---|---|
| Language | Java |
| Protocols | HTTP / Servlet / Spring MVC / Feign |
| Stars | Not provided in the source |
| Core Dependencies | Spring Cloud Gateway, Spring MVC, OpenFeign, Spring Security, Servlet API |
The responsibility boundaries of the four interception mechanisms are easiest to understand in one table
In a microservices architecture, all four components operate before or after a request enters or leaves a system, but their interception points are completely different. To decide which one to use, focus on three things: execution location, Spring dependency, and whether it targets service-to-service calls.
| Component | Layer | Primary Responsibility | Can Use Spring Beans | Typical Scenarios |
|---|---|---|---|---|
| Gateway Filter | Gateway entry layer | Global authentication, routing, rate limiting, header processing | Yes | Centralized JWT validation, route forwarding |
| Servlet Filter | Servlet container layer | Basic filtering, encoding, simple CORS handling | Usually does not directly depend on business Beans | Encoding setup, basic pre-processing |
| HandlerInterceptor | Spring MVC layer | Fine-grained control before and after Controller execution | Yes | Granular authorization, logging, auditing |
| Feign RequestInterceptor | HTTP client layer | Outbound request header enrichment | Yes | Token propagation, trace identifier forwarding |
A simple way to remember the four layers
Use the gateway for unified entry control, MVC for internal service-level business control, Servlet Filters for container-level foundational processing, and Feign for outbound service-call enhancement.
// Memory order: entry -> container -> MVC -> outbound call
GatewayFilter // Pre-processing control at the microservice entry point
Filter // Tomcat/Servlet container-level filtering
HandlerInterceptor // Enhancement before and after Spring MVC Controller execution
RequestInterceptor // Feign outbound request enhancement
This code helps you build a quick mental model of where these four components sit along the request flow.
Gateway Filters should own unified entry-layer authentication
A Gateway Filter sits in front of all microservices and acts as the first gate in the entire request chain. It is the best place for logic that every request must pass through exactly once, such as JWT validation, blacklist checks, centralized CORS handling, canary routing, and rate limiting.
Its real advantage is not complex business decisions, but global consistency. If a request does not pass gateway validation, it should never reach any downstream service. This significantly reduces duplicated code and security gaps.
The gateway is the best place for one-time JWT validation
@Component
public class AuthGlobalFilter implements GlobalFilter {
@Override
public Mono
<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
// Core logic: reject the request immediately when the token is missing
if (token == null || token.isBlank()) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
// Core logic: after successful authentication, write user info into headers for downstream services
ServerHttpRequest request = exchange.getRequest().mutate()
.header("userId", "1001")
.build();
return chain.filter(exchange.mutate().request(request).build());
}
}
This example shows how the gateway can uniformly intercept requests, validate tokens, and propagate user identity to downstream services.
Servlet Filters are better suited for container-level foundational processing
A Servlet Filter belongs to the Servlet specification and runs on top of containers such as Tomcat, before the DispatcherServlet. It is well suited for tasks that are only loosely related to business logic but strongly tied to fundamental request properties, such as character encoding setup, request wrapping, and basic CORS response headers.
Its limitation is equally clear: it is not the right place for complex authorization logic. Even though a Filter can integrate with Spring through registration in Spring Boot, its original design goal was never fine-grained business authorization.
You should prioritize a Servlet Filter in these situations
If you only need to handle character sets, request-body wrapping, or top-level access logging before Controller execution, a Filter is the safest choice. If the requirement involves role, menu, or resource-level authorization, move to an MVC Interceptor or the Spring Security filter chain.
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// Core logic: set unified encoding to avoid garbled Chinese characters
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
}
This code applies consistent request and response encoding at the Servlet container layer.
Spring MVC Interceptors are ideal for fine-grained authorization inside a service
A HandlerInterceptor works inside Spring MVC and surrounds Controller execution. It can access the handler method and request parameters, and it integrates naturally with Spring Beans. That makes it especially suitable for secondary authorization within a service, audit logging, and endpoint-level permission checks.
If the gateway has already validated the JWT, the MVC Interceptor can take the next step and decide whether this user may access this specific endpoint. Those checks usually depend on a database, cache, or permission service, which is exactly where an Interceptor shines.
The MVC Interceptor is the most business-aware layer
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String userId = request.getHeader("userId");
// Core logic: read user info from request headers and perform business-level validation
if (userId == null || userService.isForbidden(userId)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return false;
}
return true;
}
}
This example demonstrates how an MVC Interceptor can depend on Spring Beans to enforce business-level authorization.
Feign Interceptors specifically solve context propagation in service-to-service calls
A Feign RequestInterceptor does not process browser entry requests. It only processes outbound HTTP requests sent from the current service to downstream services. The most common use cases are token propagation, traceId forwarding, and tenant-context enrichment.
When user identity disappears somewhere in the call chain, the root cause is often not missing gateway validation. The real issue is that when Service A calls Service B, it fails to write user context back into the outbound request headers. Only a Feign Interceptor can solve that problem cleanly.
Token propagation is a classic Feign Interceptor responsibility
@Configuration
public class FeignTokenConfig {
@Bean
public RequestInterceptor requestInterceptor() {
return template -> {
// Core logic: read the user token from local context
String token = UserContextHolder.getToken();
if (token != null) {
// Core logic: propagate the authentication header to downstream services
template.header("Authorization", token);
}
};
}
}
This code automatically appends the authentication header to Feign outbound requests, so you do not have to duplicate token propagation logic at every call site.
Spring Security lives in the Filter chain and provides in-service security fallback
At its core, Spring Security is a FilterChain. It runs before the DispatcherServlet, which makes it especially suitable for authentication, authorization, exception translation, and security context initialization.
A typical order looks like this: the request enters Tomcat, passes through the Spring Security filter chain, then other Filters, then reaches the DispatcherServlet, and only after that does it hit the MVC Interceptor and Controller.
Security context is usually established inside each service rather than persisted in the gateway
The gateway should only identify the user and propagate the result. It should not hold each microservice’s local UserContext. Every service should read user information from request headers in its own Security Filter or MVC Interceptor and then write it into its local context.
// Core logic: write the authenticated user identity into the SecurityContext after successful authentication
SecurityContextHolder.getContext().setAuthentication(authentication);
This line shows how Spring Security establishes a standard user context inside a service for later authorization and business access.
A typical microservice call chain can be understood this way
A browser request first reaches the gateway, where JWT validation and routing happen. After the downstream service receives the request, a Security Filter or MVC Interceptor reads the headers and builds the local UserContext. If that service calls another service, the Feign Interceptor propagates the identity further downstream.
AI Visual Insight: This diagram shows the layered propagation path of a microservice request from the entry point to downstream services. It typically includes the client, gateway, service discovery, concrete business services, and the positions of interception components. Most importantly, it visualizes the flow of entry authentication, in-service processing, and service-to-service propagation, making it clear that these filters and interceptors are not interchangeable alternatives, but components distributed across different execution nodes.
The recommended implementation split is straightforward
- Gateway Filter: unified entry authentication, blacklists, and rate limiting.
- Spring Security / Servlet Filter: in-service security pre-processing and foundational filtering.
- MVC Interceptor: endpoint-level fine-grained authorization, logging, and auditing.
- Feign Interceptor: propagation of tokens, traceId values, and tenant information.
The final selection principle should be based on execution location, not on the name
All of them include words like “filter” or “interceptor,” but you should not choose based on the name. Choose based on where they execute. Put entry concerns in the gateway, container concerns in Filters, Controller-adjacent concerns in MVC, and outbound service concerns in Feign.
In enterprise projects, the most stable combination is usually this: let the gateway handle unified JWT authentication, keep Spring Security inside services as a fallback layer, use MVC Interceptors for fine-grained authorization, and use Feign Interceptors for end-to-end identity propagation.
The FAQ section answers the most common design questions
Q1: Should JWT validation happen in the gateway or inside each service?
A: Put it in the gateway first for centralized validation, so every service does not have to parse the token repeatedly. For core services, you can also add a second layer of validation with Spring Security to build a defense-in-depth model.
Q2: Why does user identity get lost during Feign calls?
A: Because a service-to-service call is a new HTTP request. Thread-local context does not automatically propagate across services, so you must use a Feign Interceptor to write the token or userId into the outbound request headers.
Q3: How should I choose between a Servlet Filter and an MVC Interceptor?
A: Use a Filter for foundational capabilities such as encoding, CORS, and request wrapping. Use a HandlerInterceptor when you need Spring Beans, access to handler information, or business-level authorization logic.
Core summary: This article systematically explains the responsibility boundaries, execution locations, and selection principles of Gateway Filters, Servlet Filters, Spring MVC HandlerInterceptors, and Feign RequestInterceptors. It highlights how JWT authentication, token propagation, UserContext storage, and Spring Security collaborate across a microservice request chain.