The gateway-service is the single entry point for all requests. Beyond routing, it enforces authentication: before forwarding any request to a secured service, it checks for a valid JWT cookie and resolves the caller's identity. This is done through two components — RouterValidator and AuthorizationFilter.
1. How Authorization Works
The Gateway uses Spring Cloud Gateway's GlobalFilter mechanism. Every request passes through AuthorizationFilter before being routed. The filter follows this decision tree:
flowchart TD
A[Incoming request] --> B{RouterValidator\nisSecured?}
B -- No --> C[Forward to service]
B -- Yes --> D{Cookie\n__store_jwt_token\npresent?}
D -- No --> E[401 Unauthorized]
D -- Yes --> F[POST /auth/solve\nwith JWT]
F --> G{Valid token?}
G -- No --> E
G -- Yes --> H[Add id-account header\nAdd Authorization header]
H --> C
When the token is valid, the filter enriches the downstream request with two headers:
Header
Value
Purpose
id-account
Account UUID from token
Services use this to identify the caller
Authorization
Bearer <jwt>
Standard bearer token for downstream services
This means downstream microservices never need to parse JWTs themselves — the Gateway handles it and passes the resolved identity as a plain header.
2. Full Request Sequence
sequenceDiagram
autonumber
actor User
User->>+Gateway: request with cookie __store_jwt_token
Gateway->>+AuthorizationFilter: filter(exchange, chain)
AuthorizationFilter->>RouterValidator: isSecured.test(request)
RouterValidator-->>AuthorizationFilter: true
AuthorizationFilter->>AuthorizationFilter: read cookie value
AuthorizationFilter->>+Auth Service: POST /auth/solve (token)
Auth Service->>Auth Service: JwtService.getId(token)
Auth Service-->>-AuthorizationFilter: { idAccount: "..." }
AuthorizationFilter->>AuthorizationFilter: mutate request headers
AuthorizationFilter->>-Gateway: chain.filter(mutated exchange)
Gateway->>-User: service response
3. The gateway-service Module
3.1 Repository
Create a new git repository for the gateway service and add it as a submodule:
Use Spring Initializr to generate a Maven project with the following settings:
Group:store
Artifact:gateway-service
Package name:store.gateway
Packaging: Jar
Java: 25
Dependencies to add:
Gateway (spring-cloud-starter-gateway-server-webflux) — reactive gateway with routing and filter support
Reactive Web (spring-boot-starter-webflux) — reactive stack required by Spring Cloud Gateway
Lombok — compile-time boilerplate reduction
Reactive stack
Spring Cloud Gateway runs on Project Reactor (WebFlux), not on the traditional servlet stack. This is why AuthorizationFilter returns Mono<Void> instead of void, and why the HTTP client inside it uses WebClient instead of RestTemplate.
Minimal REST controller; exposes a root health-check endpoint
RouterValidator
Holds the list of open routes; provides an isSecured predicate
AuthorizationFilter
Global filter; validates the JWT cookie and enriches the request
3.3 RouterValidator in detail
RouterValidator defines which routes bypass authentication. It stores them as "METHOD /path" strings and exposes an isSecured predicate. A request matches an open route if the HTTP method and path both match (with optional /** wildcard support).
Any request not matching this list returns true from isSecured, meaning the filter will require a valid cookie.
3.4 Application configuration
The application.yaml defines the CORS policy and the route table. Routes map URL patterns to upstream service hostnames (resolved inside the Docker Compose network):
Done! The security layer is complete. Every request to a secured route now passes through the Gateway, which validates the JWT cookie with auth-service and forwards the resolved identity to downstream services — without any service needing to parse tokens themselves.