Spring Cloud Gateway: Role-Based Authorization, Rate Limiting & Logging
(Java 25 | Centralized Config | Docker Ready)
π¨βπ» I'm Praveen Gupta, a Senior Backend Engineer with over 10+ years of experience in designing scalable backend systems using Java, Spring Boot, Microservices, and AWS Cloud. I specialize in building cloud-native applications, integrating DevOps practices, and mentoring teams in writing clean, production-grade code. I created this blog to share real-world backend architecture tips, Spring Boot patterns, and practical coding solutions that help developers grow faster.
In the previous part, we implemented JWT token validation at Spring Cloud Gateway.
Now weβll level it up to production standards by adding:
Role-based authorization
API rate limiting
Centralized request logging
Clear separation of public vs protected APIs
π Role-Based Authorization at Gateway
Instead of just validating the token, the Gateway will now check user roles.
Token Payload Example
{
"sub": "praveen",
"roles": ["USER", "ADMIN"],
"exp": 1712345678
}
π§ Authorization Flow

Steps
Gateway extracts JWT
Validates signature & expiry
Extracts roles
Matches roles against the API requirement
Allows or blocks the request
π‘οΈ Role-Based Gateway Filter
@Component
public class RoleAuthFilter implements GatewayFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = JwtUtil.extractToken(exchange);
List<String> roles = JwtUtil.extractRoles(token);
String path = exchange.getRequest().getURI().getPath();
if (path.startsWith("/admin") && !roles.contains("ADMIN")) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
π£οΈ Route Configuration with Roles
gateway.properties
spring.cloud.gateway.routes[0].id=product-service
spring.cloud.gateway.routes[0].uri=http://product-service:8082
spring.cloud.gateway.routes[0].predicates[0]=Path=/products/**
spring.cloud.gateway.routes[0].filters[0]=JwtAuthFilter
spring.cloud.gateway.routes[0].filters[1]=RoleAuthFilter
π¦ Rate Limiting at Gateway
Rate limiting protects services from abuse and accidental overload.
Why at Gateway?
β One place
β No code changes in services
β Scales horizontally
π Rate Limit Architecture


βοΈ Simple Rate Limiting Filter (In-Memory)
@Component
public class RateLimitFilter implements GatewayFilter {
private final Map<String, AtomicInteger> requestCounts = new ConcurrentHashMap<>();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
requestCounts.putIfAbsent(ip, new AtomicInteger(0));
if (requestCounts.get(ip).incrementAndGet() > 100) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
π‘ In real production, replace this with Redis-based rate limiting.
π Centralized Request Logging
Logging at Gateway gives full visibility across all services.
π§Ύ Logging Filter
@Component
public class LoggingFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
long startTime = System.currentTimeMillis();
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - startTime;
System.out.println(
exchange.getRequest().getMethod() + " " +
exchange.getRequest().getURI() +
" took " + duration + " ms"
);
})
);
}
}
π Public vs Protected APIs
Public APIs (No Token Required)
/users/login/users/register/health
Protected APIs
/products/**/admin/**
π£οΈ Public Route Configuration
spring.cloud.gateway.routes[2].id=public-user
spring.cloud.gateway.routes[2].uri=http://user-service:8081
spring.cloud.gateway.routes[2].predicates[0]=Path=/users/login
β No JWT filter
β Open access
π End-to-End API Flow


Client logs in
Receives JWT with roles
Calls protected API
Gateway:
Validates token
Checks roles
Applies rate limit
Logs request
Forwards to service
β Production Benefits
β Centralized security
β Zero duplication in services
β Easy scaling
β Cleaner microservices
β Docker & Kubernetes friendly
π¦ Dockerfile (Common for All Services)
Use the same Dockerfile structure for Gateway, User, and Product services.
Dockerfile
# Java 25 runtime
FROM eclipse-temurin:25-jdk
# App directory
WORKDIR /app
# Copy jar
COPY target/*.jar app.jar
# Expose port (actual value comes from env)
EXPOSE 8080
# Run app
ENTRYPOINT ["java","-jar","app.jar"]
β Java 25 compatible
β Lightweight runtime
β Environment-driven ports
βοΈ Centralized Config via Docker Volume
Your existing shared-config folder will be mounted inside containers.
Shared Config Structure
shared-config/
βββ application.properties
βββ gateway.properties
βββ user-service.properties
βββ product-service.properties
π Spring Config Import (All Services)
spring.config.import=optional:file:/config/application.properties
/configis mapped via Docker volume
π§± Docker Compose Configuration

docker-compose.yml
version: '3.8'
networks:
microservices-net:
services:
gateway-service:
container_name: gateway-service
build: ./gateway-service
ports:
- "8080:8080"
environment:
PORT: 8080
APP_NAME: gateway-service
volumes:
- ./shared-config:/config
networks:
- microservices-net
depends_on:
- user-service
- product-service
user-service:
container_name: user-service
build: ./user-service
ports:
- "8081:8081"
environment:
PORT: 8081
APP_NAME: user-service
volumes:
- ./shared-config:/config
networks:
- microservices-net
product-service:
container_name: product-service
build: ./product-service
ports:
- "8082:8082"
environment:
PORT: 8082
APP_NAME: product-service
volumes:
- ./shared-config:/config
networks:
- microservices-net
π Service-to-Service Communication
Inside Docker network:
| Service | URL Used |
| Gateway β User | http://user-service:8081 |
| Gateway β Product | http://product-service:8082 |
β Docker DNS resolves service names automatically
β No Eureka required (optional later)
π§ͺ Running the Setup
Step 1: Build JARs
mvn clean package -DskipTests
Step 2: Start All Services
docker-compose up --build
π Verify Containers
docker ps
Expected running containers:
gateway-service
user-service
product-service
π End-to-End Test
1οΈβ£ Login
POST http://localhost:8080/users/login
2οΈβ£ Access Protected API
GET http://localhost:8080/products
Authorization: Bearer <JWT>
β Gateway validates token
β Routes to Product Service
β Docker handles networking
β Why This Docker Setup Works Well
β Clean separation of concerns
β Centralized configuration
β Easy local & CI testing
β Kubernetes-ready structure
β Zero environment-specific codeπ Final Thoughts
With this setup, Spring Cloud Gateway becomes the security brain of your system, while User & Product services stay lightweight and focused on business logic.
π§± Root Project Structure
spring-cloud-gateway-microservices/
β
βββ docker-compose.yml
βββ shared-config/
β βββ application.properties
β βββ gateway.properties
β βββ user-service.properties
β βββ product-service.properties
β
βββ gateway-service/
β βββ Dockerfile
β βββ pom.xml
β βββ src/
β βββ main/
β βββ java/
β β βββ com/example/gateway/
β β βββ GatewayApplication.java
β β βββ filter/
β β β βββ JwtAuthFilter.java
β β β βββ RoleAuthFilter.java
β β β βββ RateLimitFilter.java
β β β βββ LoggingFilter.java
β β βββ util/
β β βββ JwtUtil.java
β β
β βββ resources/
β βββ application.properties
β
βββ user-service/
β βββ Dockerfile
β βββ pom.xml
β βββ src/
β βββ main/
β βββ java/
β β βββ com/example/user/
β β βββ UserServiceApplication.java
β β βββ controller/
β β β βββ AuthController.java
β β βββ dto/
β β β βββ LoginRequest.java
β β βββ util/
β β βββ JwtUtil.java
β β
β βββ resources/
β βββ application.properties
β
βββ product-service/
β βββ Dockerfile
β βββ pom.xml
β βββ src/
β βββ main/
β βββ java/
β β βββ com/example/product/
β β βββ ProductServiceApplication.java
β β βββ controller/
β β βββ ProductController.java
β β
β βββ resources/
β βββ application.properties
β
βββ README.md
π Whatβs Next (Final Part)
If you want, next we can cover:
Redis-based rate limiting
Spring Security + Gateway
OpenAPI + Swagger via Gateway
Distributed tracing (Zipkin)
Kubernetes ingress migration
Complete GitHub repo structure
π¬ Feedback?
If you found this useful, leave a comment or connect with me on LinkedIn. π
