Skip to content

Auth Proxy

The auth-proxy is a standalone HTTP gateway that lets external services reuse Aether’s identity model and Casbin ACL engine without speaking the gateway’s gRPC protocol. It connects to the same PostgreSQL database as the Aether gateway, reads the acl_rules table via the Casbin enforcer, and validates every inbound HTTP request before the request reaches its destination.

Two operating modes are supported. In proxy mode (the default) the binary acts as a reverse proxy: it authenticates the caller, evaluates workspace ACL, injects trusted X-Auth-* identity headers, strips the Authorization header, then forwards the request to a configured backend. In verify mode it exposes a single /auth/verify endpoint compatible with nginx auth_request and Envoy ext_authz — it returns 200 with identity headers on success or 401/403 on failure, and all routing decisions stay with the upstream proxy.

  • Fronting a service (such as MemoryLayer) that needs Aether-validated identity headers but cannot consume the gateway’s gRPC API directly.
  • Integrating nginx auth_request or Envoy ext_authz into an existing infrastructure stack while reusing Aether’s ACL rules.
  • Adding browser-based OAuth login (Azure, Google, or any OIDC provider) to a service that would otherwise require API-key–only access.
  • Providing token-HMAC parity with the gateway so API keys issued by Aether validate identically in the sidecar path.
Browser / Service
│ Authorization: Bearer <token>
▼
┌─────────────────┐
│ auth-proxy │ :8080
│ (proxy mode) │
│ │──── acl_rules ─────► PostgreSQL
│ Casbin ACL │◄─── api_tokens ────► (shared with gateway)
│ Composite auth │
│ Identity hdrs │
└────────┬────────┘
│ X-Auth-User, X-Auth-Tenant, …
▼
Backend service
(e.g. MemoryLayer)

The binary builds a CasbinEnforcer directly from the shared acl_rules table — no Aether gateway connection is required at runtime. Credentials are verified in order: API key (always active when a DB is present), OAuth/JWT bearer token (optional), and Azure Entra JWT (optional). A CompositeAuthenticator tries each method in turn and returns the first match. When AUTH_PROXY_LOGIN_PROVIDERS is set, a session-cookie authenticator is also appended to the chain.

After authentication, workspace ACL is evaluated using the same Casbin model as the gateway. Fail-closed semantics apply: a missing ACL rule denies access.

Callers may supply X-Aether-Grant-ID, X-Aether-Subject-Type, and X-Aether-Subject-ID headers to assert an OBO authority grant. The proxy validates the grant against the ACL service before injecting authority headers downstream. Requests without a resolver configured receive 501 Not Implemented.

Terminal window
# Minimum: proxy mode against a local backend
export AUTH_PROXY_DB_URL="postgres://aether:secret@localhost:5432/aether?sslmode=disable"
export AUTH_PROXY_BACKEND_URL="http://localhost:61001"
export AUTH_PROXY_TENANT_ID="default"
go run ./server/cmd/auth-proxy

The proxy listens on :8080. All requests are authenticated and forwarded to the backend with X-Auth-* identity headers injected.

Terminal window
# Verify mode (nginx auth_request / Envoy ext_authz)
export AUTH_PROXY_MODE=verify
export AUTH_PROXY_DB_URL="postgres://aether:secret@localhost:5432/aether?sslmode=disable"
go run ./server/cmd/auth-proxy
# nginx: auth_request http://auth-proxy:8080/auth/verify;

All configuration is via environment variables. There is no YAML config file for this binary — LoadConfigFromEnv() reads AUTH_PROXY_* directly at startup.

Environment variableDefaultDescription
AUTH_PROXY_DB_URLrequiredPostgreSQL DSN (shared with Aether gateway).
AUTH_PROXY_MODEproxyproxy — reverse-proxy with header injection. verify — auth-only for nginx/Envoy.
AUTH_PROXY_LISTEN_ADDR:8080HTTP (or HTTPS) listen address.
AUTH_PROXY_BACKEND_URLhttp://localhost:61001Upstream URL in proxy mode.
AUTH_PROXY_TENANT_IDdefaultTenant identifier injected into X-Auth-Tenant and related headers.
AUTH_PROXY_LOG_LEVELinfoStructured log level: debug, info, warn, error.
AUTH_PROXY_CORS_ORIGIN(none)Sets Access-Control-Allow-Origin; enables CORS middleware when non-empty.
AUTH_PROXY_REDIS_ADDR(none)Optional Redis for token cache and session store fallback.
AUTH_PROXY_TOKEN_HMAC_KEY(none)HMAC-SHA256 key for token hashing — must match the gateway’s key.
AUTH_PROXY_SECRETS_FILE(none)Path to gateway-generated secrets JSON (alternative to explicit HMAC key).
AUTH_PROXY_TLS_CERT_FILE(none)PEM certificate file for HTTPS.
AUTH_PROXY_TLS_KEY_FILE(none)PEM private key file for HTTPS.
Environment variableDefaultDescription
AUTH_PROXY_OAUTH_ISSUER(none)Issuer URL for bearer-token validation. Enables OAuth auth when set.
AUTH_PROXY_OAUTH_JWKS_URL(none)JWKS endpoint URL.
AUTH_PROXY_OAUTH_AUDIENCE(none)Expected aud claim.
AUTH_PROXY_OAUTH_VERIFY_SIGNATUREtrueSet false only with AETHER_DEV_MODE=true.
Environment variableDefaultDescription
AUTH_PROXY_ENTRA_TENANT_ID(none)Entra tenant ID. Enables Entra auth when set together with client ID.
AUTH_PROXY_ENTRA_CLIENT_ID(none)Entra application (client) ID.
AUTH_PROXY_ENTRA_ALLOWED_TENANTS(none)Comma-separated whitelist of acceptable Entra tid values.
AUTH_PROXY_ENTRA_VERIFY_SIGNATUREtrueSet false only with AETHER_DEV_MODE=true.
Environment variableDefaultDescription
AUTH_PROXY_ALLOWED_EMAIL_DOMAINS(none)Comma-separated email-domain allow-list applied during single-tenant login.

Login flow is disabled by default. Set AUTH_PROXY_LOGIN_PROVIDERS to enable it. When enabled, the following routes are mounted:

RouteDescription
GET /auth/login/<name>Initiates the OIDC redirect for provider <name>.
GET /auth/callback/<name>OAuth callback handler; issues a session cookie.
GET /auth/logoutClears the session cookie.
GET /auth/meReturns the current session identity as JSON.
GET /auth/checkzLightweight session liveness check.
Environment variableDefaultDescription
AUTH_PROXY_LOGIN_PROVIDERS(empty — login disabled)Comma-separated provider names, e.g. azure,google.
AUTH_PROXY_LOGIN_<NAME>_ISSUER(none)OIDC issuer URL for provider <NAME>.
AUTH_PROXY_LOGIN_<NAME>_CLIENT_ID(none)OAuth client ID.
AUTH_PROXY_LOGIN_<NAME>_CLIENT_SECRET(none)OAuth client secret.
AUTH_PROXY_LOGIN_<NAME>_REDIRECT_URL(none)OAuth redirect URL (/auth/callback/<name>).
AUTH_PROXY_LOGIN_<NAME>_SCOPES(provider default)Additional OAuth scopes (comma-separated).
AUTH_PROXY_LOGIN_<NAME>_ALLOWED_TENANTS(none)Per-provider tenant allow-list.
Environment variableDefaultDescription
AUTH_PROXY_SESSION_STOREredisredis (opaque token) or jwt (signed cookie).
AUTH_PROXY_SESSION_COOKIE_NAMEaether_sessionCookie name.
AUTH_PROXY_SESSION_COOKIE_DOMAIN(none)Cookie Domain attribute.
AUTH_PROXY_SESSION_COOKIE_SECUREtrueCookie Secure attribute.
AUTH_PROXY_SESSION_COOKIE_SAMESITElaxCookie SameSite: lax, strict, or none.
AUTH_PROXY_SESSION_TTL24hSession lifetime (Go duration string).
AUTH_PROXY_SESSION_JWT_SIGNING_KEY(none)HS256 signing key (min 32 bytes); required when SESSION_STORE=jwt.
AUTH_PROXY_SESSION_REDIS_ADDRfalls back to AUTH_PROXY_REDIS_ADDRRedis address for session storage.
AUTH_PROXY_SESSION_REDIS_PASSWORD(none)Redis password.
AUTH_PROXY_SESSION_REDIS_DB0Redis logical DB index.
AUTH_PROXY_SESSION_REDIS_PREFIXauth-session:Redis key prefix.

Full list: see Environment Variables.

EndpointAuth requiredDescription
GET /healthzNoLiveness probe. Returns {"status":"ok"} with HTTP 200.
ANY /auth/verifyYesAuth-verify endpoint for nginx/Envoy. Returns 200 + identity headers or 401/403.
ANY /YesProxy mode only: authenticates and forwards to backend.

Pass both AUTH_PROXY_TLS_CERT_FILE and AUTH_PROXY_TLS_KEY_FILE to enable HTTPS. When either is absent, the server falls back to plaintext HTTP and logs a warning. In production, terminate TLS at the proxy or provide certificates directly.

GET /healthz returns {"status":"ok"} once the server is accepting connections. There is no separate readiness endpoint — use a startup probe that checks /healthz after allowing time for the PostgreSQL connection to establish (typically a few seconds).

  • Sidecar (proxy mode): deploy alongside the backend service in the same pod or network namespace. The backend need not be reachable from outside the pod.
  • Centralised verify (verify mode): deploy as a shared service; configure nginx auth_request or Envoy ext_authz to call /auth/verify. Identity headers are returned to nginx/Envoy for forwarding.
  • The auth-proxy shares the Aether PostgreSQL database but maintains no tables of its own. It uses a conservative connection pool (10 max, 5 idle, 5-minute lifetime).

Startup fails: AUTH_PROXY_DB_URL is required The only required variable is the database DSN. Set AUTH_PROXY_DB_URL before starting.

Startup fails: failed to connect to PostgreSQL The proxy pings the database within a 5-second timeout. Verify network connectivity, credentials, and that the acl_rules table exists (created by the gateway’s migrations).

API keys return 401 after migration If the gateway is configured with a token HMAC key, the auth-proxy must use the same key. Set AUTH_PROXY_TOKEN_HMAC_KEY to the same value, or point AUTH_PROXY_SECRETS_FILE at the gateway’s generated secrets file.

JWT signature verification fails at startup Setting AUTH_PROXY_OAUTH_VERIFY_SIGNATURE=false or AUTH_PROXY_ENTRA_VERIFY_SIGNATURE=false without AETHER_DEV_MODE=true causes a hard startup error by design. Only disable signature verification in development environments.

Login providers fail with redis ping error When AUTH_PROXY_LOGIN_PROVIDERS is set and AUTH_PROXY_SESSION_STORE=redis (the default), a reachable Redis instance is required. Either set AUTH_PROXY_SESSION_REDIS_ADDR, or fall back to AUTH_PROXY_SESSION_STORE=jwt with a 32-byte signing key.

Requests return 403 with no matching ACL rule The Casbin enforcer is fail-closed. Add an ACL rule in the gateway’s admin UI (or directly in the acl_rules table) granting the principal read access to the target workspace.