API Gateway
The API Gateway is the single entry point for all client traffic in AEGIS. It is a Go reverse proxy that handles authentication, rate limiting, CORS, and request routing to the appropriate backend microservice.
Overview
Every request from the frontend (or any external client) passes through the API Gateway on port 8000 before reaching a backend service. The gateway validates the JWT (from the Authorization header or the aegis_token cookie), enforces rate limits, attaches CORS headers, and rewrites URL paths before proxying requests to the correct upstream service.
The gateway strips CORS headers from backend responses to ensure it is the single source of truth for cross-origin policy.
Port & Language
| Property | Value |
|---|---|
| Port | 8000 |
| Language | Go 1.21+ |
| Framework | net/http standard library |
| Entry point | cmd/gateway/main.go |
Middleware Stack
Requests pass through the middleware chain in this order:
Client Request → CORS → Rate Limiter → Auth → Route Handler → Backend Service1. CORS Middleware
Adds permissive CORS headers to every response and short-circuits OPTIONS preflight requests with a 200 OK.
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400Backend CORS headers are stripped by the reverse proxy’s ModifyResponse hook to prevent conflicts.
2. Rate Limiter
Per-client token bucket rate limiter using golang.org/x/time/rate:
- Rate: 100 requests per minute (~1.67 req/sec)
- Burst: 10 requests
- Key: authenticated
user_idfrom context, or remote IP address as fallback
When the limit is exceeded, the gateway returns 429 Too Many Requests.
3. Auth Middleware
Validates the JWT and injects user_id and roles into the request context. Authentication is JWT only — the gateway no longer accepts the X-API-Key header.
Where the JWT is read from (in order):
Authorization: Bearer <token>header — the standard case for API clients.aegis_tokencookie — fallback for browser SSE/EventSource clients that cannot set headers.
The token is validated locally using HMAC-SHA256 with the JWT_SECRET environment variable. A missing or invalid token returns 401 Unauthorized.
Unauthenticated routes (auth skipped):
/health/api/v1/auth/token/api/v1/entity-types*/api/v1/relationship-rules*/api/v1/relationship-types*
For local development, obtain a token by logging in with admin@aegis.local / aegis-dev-admin at POST /api/v1/auth/token. That user has admin, operator, and reviewer roles.
Routing Rules
The gateway maps public API paths (prefixed with /api/v1/) to internal service paths. Each upstream service is configured via environment variables with sensible localhost defaults.
Route Table
| Public Path | Upstream Service | Internal Path | Notes |
|---|---|---|---|
/api/v1/conversations* | Orchestration (8001) | /conversations* | |
/api/v1/agents/{id}/execute | Orchestration (8001) | /execute | POST only |
/api/v1/agents/{id}/stream/{conv_id} | Orchestration (8001) | /conversations/{conv_id}/stream | SSE streaming |
/api/v1/approvals* | Approval (8004) | /approvals* | |
/api/v1/graph/context/managed/{id} | Knowledge Graph (8003) | /context/assemble/managed/{id} | R27 managed entities |
/api/v1/graph/context/{well_api} | Knowledge Graph (8003) | /context/assemble/{well_api} | Legacy well context |
/api/v1/graph/entities/* | Knowledge Graph (8003) | /entities/* | |
/api/v1/impact/* | Knowledge Graph (8003) | /impact/* | |
/api/v1/admin/* | Knowledge Graph (8003) | /admin/* | Requires admin role |
/api/v1/entity-types* | Knowledge Graph (8003) | /entity-types* | Public (no auth) |
/api/v1/relationship-types* | Knowledge Graph (8003) | /relationship-types* | Public (no auth) |
/api/v1/relationship-rules* | Knowledge Graph (8003) | /relationship-rules* | Public (no auth) |
/api/v1/detection-rules* | Knowledge Graph (8003) | /event-detection-rules* | Requires power_user or admin |
/api/v1/entities* | Knowledge Graph (8003) | /managed-entities* | R25 managed CRUD |
/api/v1/ingest/csv | Ingestion (8005) | /ingest/operator/csv | |
/api/v1/ingest/* | Ingestion (8005) | /ingest/* | |
/api/v1/compliance/summary | Orchestration (8001) | /compliance/summary | R1.2 dashboard |
/api/v1/compliance/matrix | Orchestration (8001) | /compliance/matrix | R1.2 dashboard |
/api/v1/compliance/charts/* | Orchestration (8001) | /compliance/charts/* | R1.2 dashboard |
/api/v1/compliance/assess* | Orchestration (8001) | /compliance/assess* | |
/api/v1/compliance/* | Compliance (8006) | /compliance/* | Legacy endpoints |
/api/v1/checklists* | Orchestration (8001) | /checklists* | R1.3 |
/api/v1/rules* | Orchestration (8001) | /rules* | R1.5 |
/api/v1/workspaces/* | Orchestration (8001) | /workspaces/* | R1.4 SSE streaming |
/api/v1/events* | Flaring (8007) | /events* | Operational events |
/api/v1/flare-events* | Flaring (8007) | /flare-events* | |
/api/v1/repair-obligations* | Flaring (8007) | /repair-obligations* | |
/api/v1/authorizations/* | Flaring (8007) | /authorizations/* | |
/api/v1/alerts/* | Flaring (8007) | /alerts/* | |
/api/v1/flaring/* | Flaring (8007) | /flaring/* | Legacy routes |
/api/v1/auth/* | Auth (8009) | /auth/* | |
/health | Gateway (local) | — | Returns {"status":"ok"} |
Role-Based Access Control
Some routes enforce role checks before proxying:
/api/v1/admin/*— Requires theadminrole. Returns403 Forbiddenotherwise./api/v1/detection-rules*— Requirespower_useroradminrole.
Roles are extracted from the authenticated JWT claims and placed into the request context by the auth middleware.
Architecture
cmd/gateway/main.go # Entry point, middleware chain assembly
internal/
├── auth/
│ └── jwt.go # JWT parsing, validation, generation (HS256)
├── middleware/
│ ├── auth.go # Auth middleware (JWT only — header or cookie)
│ ├── cors.go # CORS header injection
│ └── ratelimit.go # Per-client token bucket rate limiter
└── proxy/
└── routes.go # Route registration, reverse proxy setupJWT Claims Structure
type Claims struct {
UserID string `json:"user_id"`
Roles []string `json:"roles"`
jwt.RegisteredClaims
}Tokens are signed with HS256 and expire after 24 hours. The issuer is set to aegis-gateway.
Dependencies
| Dependency | Version | Purpose |
|---|---|---|
github.com/golang-jwt/jwt/v5 | v5.2.1 | JWT parsing and generation |
golang.org/x/time | v0.5.0 | Token bucket rate limiter |
The gateway has no database dependencies. It proxies all persistence to backend services.
Service Dependencies
The gateway calls the auth-service (port 8009) for token generation. JWT validation is done locally using the shared JWT_SECRET. All other backend services are called only as reverse proxy targets.
Configuration
| Environment Variable | Default | Description |
|---|---|---|
API_GATEWAY_PORT | 8000 | Port the gateway listens on |
JWT_SECRET | aegis-local-dev-secret-change-in-production | HMAC secret for JWT signing/validation |
ORCHESTRATION_URL | http://localhost:8001 | Orchestration engine upstream |
MEMORY_URL | http://localhost:8002 | Memory service upstream |
KNOWLEDGE_GRAPH_URL | http://localhost:8003 | Knowledge graph service upstream |
APPROVAL_URL | http://localhost:8004 | Approval service upstream |
INGESTION_URL | http://localhost:8005 | Ingestion service upstream |
COMPLIANCE_URL | http://localhost:8006 | Compliance monitor upstream |
FLARING_URL | http://localhost:8007 | Flaring monitor upstream |
AUTH_URL | http://localhost:8009 | Auth service upstream |
Running Locally
cd services/api-gateway
go run ./cmd/gateway/The gateway will start on port 8000 and log the upstream service URLs it is configured to proxy to. Make sure the backend services you need are running before sending requests through the gateway.
The gateway must share the same JWT_SECRET value as the auth-service. If these values diverge, JWT validation will fail for all authenticated requests.