How to Prevent Direct Access to Microservices Using Spring Boot API Gateway
In a microservices architecture, the API Gateway is the single entry point for clients. It handles authentication, logging, routing, rate limiting, and many other cross-cutting concerns.
But there is a common mistake: Even after building an API Gateway, microservices are still directly accessible.
This means anyone can bypass the gateway and call your services directly — which is a serious security risk.
In this article, we will learn how to force all requests to go through the API Gateway and block direct access to Spring Boot microservices
We want this flow:
Client → API Gateway → Order Service → Product Service
And we want to block this:
Client → Order Service ❌
Client → Product Service ❌
Step 1 — Add a secret header in the API Gateway : The API Gateway will attach a secret key to every request sent to microservices.This secret will act as proof that the request came from the gateway.
application.yml in API Gateway
spring:
cloud:
gateway:
default-filters:
- AddRequestHeader=X-GATEWAY-TOKEN, my-super-secret-key
Now every request sent from the gateway will contain:
X-GATEWAY-TOKEN: my-super-secret-key
Step 2 — Configure the secret in microservices
In Order Service, Product Service, etc.
application.yml
gateway:
secret: my-super-secret-key
This value must be the same as the gateway token.
Step 3 — Create a filter in each microservice
This filter will check if the request contains the gateway token. If the token is missing or invalid, the request will be rejected.
Create GatewayOnlyFilter.java
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@Component
public class GatewayOnlyFilter extends OncePerRequestFilter {
@Value("${gateway.secret}")
private String gatewaySecret;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
String token = request.getHeader("X-GATEWAY-TOKEN");
if (token == null || !token.equals(gatewaySecret)) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("Direct access is not allowed");
return;
}
filterChain.doFilter(request, response);
}
}
This code ensures:
If you use Spring Security
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.addFilterBefore(new GatewayAuthFilter(),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
Step 4 — Test the behavior
Direct call to microservice (should fail)
curl http://localhost:8081/orders
Response:
403 Forbidden
Direct access is not allowed
Call through API Gateway (should succeed)
curl http://localhost:8080/orders
Response:
200 OK
[ Order data... ]
Because the API Gateway automatically adds:
X-GATEWAY-TOKEN: my-super-secret-key
Thanks for the clear explanation