Last updated 2026-06-29

Configuration

This page lists every configuration knob the service reads. All configuration is via environment variables with the GATEWAY_ prefix — the same convention as identity, so the two services deploy with one consistent style. Defaults are tuned so the service runs with zero configuration for local development; production deployments override the Postgres DSN and the service-auth tokens.

The reference table is generated directly from the service's configuration source (internal/config/config.go), so the variable names, defaults, and validation floors here can never drift from the code.

All variables

Variable Type Default Description Constraint
GATEWAY_ADMIN_API_SECRET string (empty) AdminAPISecret gates the AdminService (project configuration), presented as the `X-Admin-Secret` header. Empty disables the admin RPCs entirely. must be a high-entropy value of at least 32 characters
GATEWAY_ADMIN_RATE_LIMIT_PER_MINUTE int 30 AdminRateLimitPerMinute throttles the admin API per caller (online brute-force protection); non-positive disables the limiter.
GATEWAY_ALLOWED_ORIGINS csv (empty) AllowedOrigins is the CORS allow-list of browser origins permitted to call the API. Empty allows none.
GATEWAY_AUDIT_LOG bool false AuditLog enables an async, append-only audit log of every relation-tuple change and admin mutation (to the structured logger). Default false.
GATEWAY_CONNECT_PORT int 8080 ConnectPort is the Connect/HTTP listener serving JSON, gRPC, and gRPC-Web RPCs.
GATEWAY_DATA_REGION string (empty) DataRegion is the region this instance serves: it refuses to operate on a project pinned to a different data_region (fail closed). Empty (default) is region-agnostic — serves every project, today's behavior.
GATEWAY_DECISION_LOG bool false DecisionLog enables an async, append-only audit log of every Check/ CheckSet decision (to the structured logger). Default false.
GATEWAY_DEFAULT_PROJECT_ID string default DefaultProjectID is the project shard used for any request whose project_id is empty.
GATEWAY_DEFAULT_TENANT_ID string (empty) DefaultTenantID is the tenant pinned for requests that omit tenant_id (the project's default tenant). Empty is the conventional default.
GATEWAY_HTTP_MAX_BODY_BYTES int 1048576 HTTPMaxBodyBytes is the maximum accepted request body, in bytes. Must be positive. must be positive
GATEWAY_MAX_BATCH_CHECK_ITEMS int 1000 MaxBatchCheckItems caps the number of items in a single BatchCheck request, bounding per-request cost.
GATEWAY_MAX_CHECK_READS int 5000 MaxCheckReads caps the number of store reads (tuple lookups) a single Check/CheckSet/Expand/ListObjects evaluation may perform, bounding the per-request cost a pathological cyclic/branching graph can inflict. Non-positive uses the service default. when set, must be >= 100 (use 0/negative for the default)
GATEWAY_MAX_EXPAND_NODES int 10000 MaxExpandNodes caps the size of an Expand result tree, bounding the response a single cheap request can amplify into.
GATEWAY_MAX_LIST_OBJECTS int 1000 MaxListObjects caps the candidate set a single ListObjects call scans, bounding its full-scan + per-object Check cost.
GATEWAY_METRICS_PORT int 9090 MetricsPort serves the Prometheus /metrics endpoint and the health probes.
GATEWAY_POSTGRES_AUTO_MIGRATE bool false PostgresAutoMigrate runs the expand migration on boot when true. It defaults to FALSE: migrations are a deliberate operator step (out-of-band `workspace migrate`, an init container, or a migrate Job), so a large existing DB's first deploy can never livelock on a bounded CONCURRENTLY build inside the boot window. Opt in (true) only for small/dev DBs.
GATEWAY_POSTGRES_DSN string (empty) PostgresDSN selects the postgres driver when set; empty uses memory.
GATEWAY_SERVICE_AUTH_TOKENS csv (empty) ServiceAuthTokens are the accepted service credentials presented by calling backends as `Authorization: Bearer <token>`. This is an internal service authenticated service-to-service (not by end-user tokens); the user is passed as data in the request. Empty disables the requirement — trust the network/mesh — and the service logs a warning.
GATEWAY_TENANT_RATE_LIMIT_PER_MINUTE int 0 TenantRateLimitPerMinute throttles authz data-plane RPCs per (project, tenant); non-positive (the default) disables the limiter. when enabled, must be >= 60 (use 0 to disable)

Choosing a store: memory vs. Postgres

  • In-memory (GATEWAY_POSTGRES_DSN empty) — the default, and the conformance reference both drivers are pinned against. Data lives in process memory and is lost on restart. Use it for local development, tests, and ephemeral demos.
  • Postgres (DSN set) — durable, the only choice for production and for running more than one replica. Every table and index leads with project_id. Migrations are a deliberate operator step: GATEWAY_POSTGRES_AUTO_MIGRATE defaults to false, so run workspace migrate explicitly (see Deploy with Docker). Opt in to boot-time migration only for small or dev databases.

Service authentication

Workspaces is an internal service-to-service API: the caller is a trusted product backend, and the end user is passed as data (acting_user_id / subject_user_id) in the request body. The bearer token authenticates the calling service, not an end user. A missing or wrong credential returns HTTP 401 (Connect code Unauthenticated).

Enable service auth in production. When GATEWAY_SERVICE_AUTH_TOKENS is empty the service logs a service_auth_disabled warning at startup and accepts every caller — acceptable only behind a service mesh, mTLS, or an otherwise private network. Anywhere else, set at least one token. The list accepts several values so you can rotate credentials without downtime: add the new token, roll callers over, then drop the old one. See Security & Service Auth.

A production example

The minimum production override: a durable store and at least one service token.

docker run
docker run -p 8080:8080 -p 9090:9090 \
-e GATEWAY_POSTGRES_DSN='postgres://workspace:password@db:5432/workspace?sslmode=disable' \
-e GATEWAY_SERVICE_AUTH_TOKENS='prod-token-a,prod-token-b' \
-e GATEWAY_DEFAULT_PROJECT_ID=my-product \
-e GATEWAY_ALLOWED_ORIGINS='https://app.my-product.com' \
ghcr.io/elloloop/workspace