API Gateway / BFF
Purpose
The Gateway is the single external edge of BitVault. Every client request — web, CLI, mobile — enters here and nowhere else. It is responsible for:
- Terminating TLS and REST.
- Authenticating the request (JWT validation or token introspection against Identity).
- Extracting and validating tenant context.
- Enforcing per-tenant, per-key rate limits.
- Propagating OpenTelemetry trace context.
- Translating REST requests to internal gRPC calls against the appropriate module.
- BFF aggregation — composing multiple gRPC responses into a single REST response for web/mobile clients.
The Gateway owns no domain logic and no domain data. It orchestrates calls to modules; all decisions live downstream.
Statelessness
The Gateway is the primary horizontal-scale unit. Because it carries no mutable state, any number of replicas can run behind a load balancer without coordination. Sessions and rate-limit counters are stored in Redis, not in-process.
Middleware chain
Requests traverse a fixed middleware stack in this order:
TLS termination
→ Authentication (JWT verify / token introspection → Identity)
→ Tenant context (extract tenant_id from token claims)
→ Rate limiting (per tenant · per API key · Redis-backed)
→ Request tracing (OTel span open, trace-id propagated via gRPC metadata)
→ REST ↔ gRPC (marshal to protobuf, route to module)
→ Response (unmarshal, set headers, return)
sequenceDiagram
autonumber
participant C as Client
participant GW as API Gateway
participant RD as Redis
participant ID as Identity
participant M as Module (e.g. Files)
C->>GW: HTTPS request (Authorization: Bearer <token>)
GW->>GW: TLS termination
GW->>ID: IntrospectToken(token) [gRPC]
ID-->>GW: {tenant_id, user_id, scopes, valid}
GW->>RD: INCR rate_limit:{tenant_id}:{key} (with TTL)
RD-->>GW: current count (allow / deny)
GW->>GW: open OTel span, inject trace-id into gRPC metadata
GW->>M: gRPC call (tenant_id, user_id in metadata)
M-->>GW: gRPC response
GW-->>C: HTTP response (JSON)
:::tip The Gateway is the only component that should ever hold a raw user credential in the request path. Downstream modules receive verified tenant/user context only — never the original token. :::
Configuration
| Setting | Description | Default |
|---|---|---|
gateway.port |
HTTP listen port | 8080 |
gateway.tls.cert / key |
TLS certificate paths | required in non-local envs |
gateway.rate_limit.requests_per_second |
Tenant-level burst ceiling | 100 |
gateway.rate_limit.key_requests_per_second |
Per-API-key ceiling | 20 |
gateway.grpc.timeout |
Upstream gRPC deadline | 30s |
All values are 12-factor configurable (env vars override file config). Rate limits are tunable per-environment: local development uses generous limits; production uses tenant-plan-aware limits loaded from the Billing module.
Relation to other services
- Identity — called on every request for token introspection; result may be cached in Redis with a short TTL.
- Sharing — access check is performed before any download or content URL is issued.
- All modules — receive only verified
{tenant_id, user_id, scopes}context in gRPC metadata; they never re-validate the raw token.