Overview
Port: 4000 The Gateway is the central entry point for all frontend requests. It routes to backend services via HTTP proxy and is completely stateless — JWT signature is verified in middleware (verifyJwt) and context is passed via headers to downstream services.Proxy Routes
The public API
/v1/* routes (e.g. POST /v1/agents:from-url, GET /v1/agents/builds/:buildId, POST /v1/chat, GET /v1/contacts/export) use API-key authentication (Bearer API key, validated via the auth service) rather than JWT, and proxy to the bot service’s agent-build, chat, and contact-export routes. GET /v1/contacts/export requires the contacts:read scope and is streamed via a raw pipe (no buffered timeout).Auth Middleware
The gateway handles JWT authentication for all proxied requests:1
Extract Token
JWT is extracted from the
Authorization: Bearer header or the access_token cookie.2
Verify Signature
The gateway verifies the JWT signature with the shared secret:
3
Validate Membership
Validates that the user has at least one organization membership.
4
Attach Auth Context
Sets
request.auth with: userId, organizationId, email, platformRole, orgRole.5
Forward Headers
Forwards auth context to downstream services as headers:
user-idorganization-iduser-emailx-platform-rolex-org-role
The gateway verifies the JWT signature; downstream services trust forwarded headers. The gateway is the trust boundary — it is the only public ingress, and downstream service ports (4001–4006) are not exposed to the internet.
Every proxy scope declares its gate
Each route group registered inproxy.ts either runs authMiddleware or carries an // auth-exempt: <reason> comment directly above it (the auth-service lane, public catalogue routes, provider webhooks, the optional-auth /public/* lane, and similar). The gateway test proxy-scope-auth-guard.test.ts fails the build when a new scope has neither. When you add a route group, decide which it is and say so in the code.
Dot segments are refused
The gateway answers400 Bad Request for any request path containing a . or .. segment (including %2e spellings), a backslash, or a tab/newline, before any scope’s auth runs. Upstream URLs are built by concatenating the client’s path onto a service origin, and fetch removes dot segments — so such a path would otherwise be routed by one scope and served by the upstream as a different route. Query strings are not inspected.
Plugins
Configuration Variables
Critical Patterns
JWT Verify
JWT Verify
The gateway follows
AUTHENTICATION_PATTERN.md — the JWT signature is verified with the shared secret (verifyJwt(token, config.JWT_SECRET)). Downstream services trust requests that come through the gateway.Auth Context via Headers
Auth Context via Headers
Auth context is passed via HTTP headers to downstream services, not via cookies. Services read
request.user from their own JWT middleware that parses these headers.Multipart Upload Handling
Multipart Upload Handling
Custom parser passes raw buffer for multipart uploads. The realtime-audio service has a 50MB upload limit for voice samples.
Service Failure Handling
Service Failure Handling
When a downstream service is unavailable, the gateway returns
503 with a descriptive error message.Hop-by-Hop Header Filtering
Hop-by-Hop Header Filtering
Headers like
host, connection, and transfer-encoding are filtered before forwarding to downstream services.
