Skip to main content

Overview

sgivu-gateway is the API Gateway and Backend-for-Frontend (BFF) for the SGIVU ecosystem. Built with Spring Cloud Gateway (WebFlux), it serves as:
  • BFF for the SPA, providing /auth/session and authentication flows
  • Proxy and Router for all business APIs (/v1/*) with security, circuit breakers, route rewriting, and fallbacks

Technologies

  • Java: 21
  • Spring Boot: 3.5.8
  • Spring Cloud Gateway: WebFlux-based routing
  • Spring Security: OAuth2 client + Resource Server
  • Spring Session: Redis-based session management
  • Resilience4j: Circuit breaker pattern
  • Micrometer Tracing: Zipkin integration
  • SpringDoc OpenAPI: Swagger UI aggregation
  • Lombok: Code generation

Port Configuration

  • Default Port: 8080 (configurable via PORT or config server)

Prerequisites

  • JDK 21
  • Maven 3.9+
  • Docker & docker-compose
  • Redis: Session storage (defined as sgivu-redis in docker-compose)
  • Required Services: sgivu-config, sgivu-discovery, sgivu-auth

Endpoints

BFF Endpoints

GET /auth/session
public
Returns current session information: subject, username, roles, isAdmin

Proxied Routes

/docs/<service>/...
public
Aggregated Swagger documentation from microservices
/v1/*
protected
Business APIs requiring authentication and authorization
  • Token relay enabled
  • Circuit breaker with fallback
  • Automatic service discovery via Eureka
GET /fallback/*
public
Fallback endpoints when downstream services fail
GET /actuator/health
public
Gateway health status

Running the Service

Development with Docker Compose

cd infra/compose/sgivu-docker-compose
docker compose -f docker-compose.dev.yml up -d

Local Execution

./mvnw clean package
./mvnw spring-boot:run

Docker Build

./build-image.bash
docker build -t stevenrq/sgivu-gateway:v1 .
docker run -p 8080:8080 --env-file infra/compose/sgivu-docker-compose/.env stevenrq/sgivu-gateway:v1

Routing Configuration

Documentation Routes

Pattern: /docs/<service>/...
  • Rewrites paths and proxies to microservice Swagger endpoints
  • Public access (no authentication required)
  • Example: /docs/user/v3/api-docshttp://sgivu-user/v3/api-docs

API Routes

Pattern: /v1/* Applied Filters:
  1. TokenRelay: Forwards OAuth2 token to downstream services
  2. CircuitBreaker: Resilience4j circuit breaker with fallback
  3. Service Discovery: Resolves services via Eureka
Protected Endpoints:
  • /v1/users/**
  • /v1/persons/**
  • /v1/companies/**
  • /v1/vehicles/**
  • /v1/purchase-sales/**
  • /v1/ml/**

ML Service Routing

Routes to Python ML service: http://sgivu-ml:8000

Global Filters

ZipkinTracingGlobalFilter

Purpose: Distributed tracing integration Actions:
  • Creates spans for each request
  • Adds X-Trace-Id header for trace correlation
  • Tags spans with HTTP status and duration

AddUserIdHeaderGlobalFilter

Purpose: User context propagation Actions:
  • Extracts subject/claim from JWT token
  • Adds X-User-ID header to downstream requests
  • Enables user tracking in microservices

Security Configuration

OAuth2 Client

Gateway acts as OAuth2 client for login flows:
  • Authorization Flow: PKCE (Proof Key for Code Exchange)
  • Client Registration: Configured in sgivu-config-repo/sgivu-gateway.yml
  • Provider: Points to sgivu-auth issuer

Resource Server

Validates JWT tokens for API routes:
  • Issuer: sgivu-auth OpenID configuration
  • JWKS Endpoint: Used for signature verification
  • Token Relay: Forwards validated token to downstream services

Public Routes

No authentication required:
  • /docs/**
  • /v3/api-docs/**
  • /swagger-ui/**
  • /oauth2/**
  • /login/**
  • /auth/session
  • /fallback/**

Protected Routes

Require valid JWT token:
  • All /v1/** endpoints

CORS Configuration

Review CORS settings in SecurityConfig to match your frontend origin:
.cors(cors -> cors.configurationSource(request -> {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowedOrigins(List.of("http://localhost:3000"));
    config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
    config.setAllowedHeaders(List.of("*"));
    config.setAllowCredentials(true);
    return config;
}))

Circuit Breaker

Configuration

Each API route includes Resilience4j circuit breaker:
filters:
  - TokenRelay=
  - CircuitBreaker=serviceCircuitBreaker,forward:/fallback/service

Fallback Behavior

When a service is unavailable:
  1. Circuit breaker opens after threshold failures
  2. Request routes to /fallback/<service>
  3. Returns graceful error response
  4. Circuit half-opens after timeout to test recovery

Session Management

Redis Configuration

Spring Session stores sessions in Redis:
spring:
  session:
    store-type: redis
  data:
    redis:
      host: ${REDIS_HOST}
      port: 6379
      password: ${REDIS_PASSWORD}
Ensure Redis is accessible and configured with password authentication in production.

Observability

Distributed Tracing

Zipkin Integration:
  • Endpoint: Configured via config server
  • Header: X-Trace-Id added to all requests
  • Spans: Created for each gateway route
Brave Configuration:
management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://sgivu-zipkin:9411/api/v2/spans

Health Checks

curl http://localhost:8080/actuator/health
Response includes:
  • Gateway status
  • Circuit breaker states
  • Downstream service availability

Testing

./mvnw test
Recommended Integration Tests:
  • Route and path rewriting (/docs/*)
  • Token relay propagation
  • Circuit breaker and fallback behavior
  • Global filter execution (X-Trace-Id, X-User-ID)

Troubleshooting

Symptoms: API requests return unauthorized or forbiddenSolutions:
  • Verify Bearer token is valid (check aud/issuer claims)
  • Ensure sgivu-auth is operational and accessible
  • Verify JWKS endpoint is reachable
  • Check token hasn’t expired
Symptoms: 503 Service Unavailable or routing errorsSolutions:
  • Verify services are registered in Eureka (http://sgivu-discovery:8761)
  • Check eureka.client.service-url.defaultZone configuration
  • Review service application names match route URIs
  • Inspect gateway logs for route resolution errors
Symptoms: Users logged out unexpectedly or session lossSolutions:
  • Verify Redis is running and accessible
  • Check REDIS_HOST and REDIS_PASSWORD environment variables
  • Review Redis logs for connection errors
  • Confirm session timeout configuration
Symptoms: All requests route to fallback endpointsSolutions:
  • Check downstream service health
  • Review circuit breaker configuration (threshold, timeout)
  • Inspect service logs for errors
  • Verify network connectivity between gateway and services
Symptoms: Browser blocks requests with CORS policy errorsSolutions:
  • Add frontend origin to allowedOrigins in SecurityConfig
  • Verify allowedMethods includes required HTTP methods
  • Check allowCredentials is set to true for cookie-based auth
  • Review browser console for specific CORS error details

Configuration Reference

Environment Variables

VariableDescriptionExample
PORTServer port8080
REDIS_HOSTRedis hostsgivu-redis
REDIS_PASSWORDRedis passwordredis_password
EUREKA_URLEureka server URLhttp://sgivu-discovery:8761/eureka/
spring.security.oauth2.client.registration.*OAuth2 client settingsVia config server
spring.security.oauth2.client.provider.*OAuth2 provider settingsVia config server

Auth Server

OAuth2 provider and JWT issuer

Discovery

Service registry for routing

Config Server

Centralized configuration

User Service

User management APIs

Build docs developers (and LLMs) love