Security, auth ordering, and rate limits
How Athena enforces authentication on sensitive routes, orders auth before body parsing, and applies optional inbound and outbound rate limits.
This page summarizes product-facing behavior for the API hardening features: who can call which routes, 401 vs 400 semantics, gateway rights, optional rate limits, and stats / fetch typing. For day-to-day integration, pair this with API Overview and the OpenAPI reference.
Storage API (/storage/*)
Authentication
- Every
/storage/*request must satisfyrequire_admin_or_gateway:- Static admin:
ATHENA_KEY_12set, and the same value sent asX-Athena-KeyorX-Athena-Admin-Key, or - Gateway API key: a valid
ath_*key inX-Athena-Keywith thegateway.storage_proxyright (storage proxy for user-supplied S3-compatible credentials).
- Static admin:
Auth before JSON (401 vs 400)
- Storage uses service middleware so authentication runs before the
Jsonbody extractor. - Callers without valid credentials get 401 Unauthorized even if the body is missing or not valid JSON.
- After a successful auth, malformed JSON or validation failures can still return 400 Bad Request (for example invalid
bucket/endpointshape).
Validation (after auth)
- Bucket names must satisfy S3 DNS-style rules (length, charset, no adjacent dots).
- Endpoint must be a URL with host only (no path, query, fragment, or userinfo). HTTPS is required unless
ATHENA_STORAGE_ALLOW_HTTP=1is set for non-TLS dev endpoints. - Optional scanner-oriented checks may return 400 for obvious automation substrings in fields.
Inbound rate limiting
- When enabled, the storage group applies after auth (per-IP, optional
X-Forwarded-Fortrust). See Inbound rate limits below.
See also Storage API.
Schema, introspection, registry, and OpenAPI
These surfaces require admin key or gateway key with read-appropriate rights (same require_admin_or_gateway pattern as other protected metadata):
GET /schema/*(clients, tables, columns, migrations, etc.)GET /clientsGET /router/registryGET /registry,GET /registry/{id}GET /openapi.yaml,GET /openapi-wss.yaml
Callers still use X-Athena-Client where the handler resolves a logical client for Postgres-backed schema reads. Health-style endpoints (for example /ping, cluster health) stay public for load balancers.
Raw SQL (/query/sql, /gateway/sql)
require_admin_or_gatewaywithgateway.query(and the request’s client binding viaX-Athena-Clientwhere applicable) runs before pool resolution.driveris restricted to an allowlist (for exampleathena,postgresql/postgres,supabase) with a short maximum length; unsupported values return 400 after auth.
Backup admin (/admin/backups/*)
- Protected by
ATHENA_KEY_12(same header rules as the static admin key) plus optional inbound rate limit groupbackup_admin. - Handlers authenticate before logging user-controlled query or body content at INFO; list filters use redacted summaries where appropriate.
Inbound rate limits
Optional per-route-group throttles (token-bucket via governor) keyed primarily by client IP, with optional use of the first hop of X-Forwarded-For when rate_limit_trust_x_forwarded_for is enabled under gateway in config (or ATHENA_RATE_LIMIT_TRUST_X_FORWARDED_FOR).
When a limit trips, Athena responds with 429 Too Many Requests and may include Retry-After.
Groups (each has _enabled, _per_second, _burst):
| Group | Typical routes |
|---|---|
storage | /storage/* (after auth) |
schema | /schema/*, related introspection |
raw_sql | /query/sql, /gateway/sql |
backup_admin | /admin/backups/* |
Config keys (under the gateway: section of config.yaml, names as loaded by the server):
rate_limit_inbound_{group}_enabledrate_limit_inbound_{group}_per_secondrate_limit_inbound_{group}_burstrate_limit_trust_x_forwarded_for
Environment overrides follow the pattern ATHENA_RATE_LIMIT_INBOUND_{GROUP}_ENABLED, ATHENA_RATE_LIMIT_INBOUND_{GROUP}_PER_SECOND, ATHENA_RATE_LIMIT_INBOUND_{GROUP}_BURST (group in uppercase, e.g. STORAGE, RAW_SQL).
Defaults keep limits off unless _enabled is set, so normal deployments are not throttled until you opt in.
Outbound Supabase rate limits
To cap egress HTTP from Athena to Supabase (for example under abuse or retry storms), configure under gateway::
rate_limit_outbound_supabase_enabledrate_limit_outbound_supabase_per_secondrate_limit_outbound_supabase_burst
When the bucket is exhausted, gateway paths that call Supabase may short-circuit with a service unavailable–style response (see server logs at debug for throttle reasons). Defaults are conservative (off or high) so legitimate bulk work is not blocked until you tune them.
Gateway fetch and stats tables
For client_statistics and client_table_statistics, equality filters on numeric and timestamp columns must not be sent to Postgres as untyped text (which can produce 42883).
Athena merges information_schema column types from your pool with a static fallback descriptor map for these tables when live metadata is empty or incomplete. That keeps string JSON filter values compatible with bigint and double precision columns.
See Gateway API for fetch usage.
Stats rollup and database indexes
Heavy INSERT … SELECT rollups from gateway_request_log / gateway_operation_log into stats tables benefit from appropriate indexes. Apply DBA-reviewed migrations such as:
sql/migrations/add_gateway_operation_log_stats_index.sql— partial index on(client, table_name, operation)forclient_table_statisticsrollups.
Operations checklist
gateway.api_key_fail_mode: usefail_closedin production so API key enforcement cannot silently allow traffic when the key store is unavailable.- OpenAPI / docs: after changing auth or status codes on routes, regenerate or sync
openapi.yamland publish docs so clients see 401 / 429 where applicable. - Invariant: no S3 SDK calls,
s3cmd, or other storage I/O for user-supplied bucket/endpoint/credentials until auth has succeeded for that request.