Skip to content

Authentication and Cookies

brookie edited this page Oct 8, 2026 · 4 revisions

Authentication and Cookies

This page covers the cookies setting (forwarding client cookies and injecting server-side ones), token authentication for database routes, and the encryption commands for storing tokens in config.

# api_dock_config/databases/secure_data.yaml
name: secure_data
authentication:
  key: api_token                  # cookie that carries the token
  values: ["Z0FBQUFB...", "Z0FBQUFC..."]   # encrypted with `api-dock encrypt`
tables:
  data: s3://private-bucket/data.parquet
routes:
  - route: data
    sql: SELECT * FROM [[data]]

A request to /secure_data/data succeeds only if its api_token cookie decrypts to one of the listed values.

Scope. Authentication is checked on database routes only. Remote proxy routes never check authentication: the upstream API checks credentials, using the cookies the remote's cookies setting lets through. To protect a remote, rely on the upstream's own auth or put API Dock behind something that enforces it. Since api_dock 0.10.0, startup logs a warning when a remote's config, or the main config while remotes are served, has an authentication block that remote routes ignore.

Where settings apply

Setting in... Database routes Remote routes
database file yes no
remote file no yes (cookies only, since authentication is ignored on remotes)
main config.yaml yes, unless the database file sets its own no: remotes don't inherit cookies or authentication

Inheritance is all-or-nothing per key: a database file that sets cookies or authentication replaces the main config's value entirely.

The cookies setting

Value Client cookies used Injected cookies
not set none (only the authentication.key cookie, if any) none
false none (only the authentication.key cookie) none
true all none
list names listed as strings, plus the authentication.key cookie dict entries in the list
cookies:
  - session_id                          # forward this client cookie
  - key: __Secure-authjs.session-token  # inject this cookie
    value: "env:UPSTREAM_SESSION_TOKEN"

Injected cookie forms

Entry Value sent
{key: NAME, value: "literal"} the literal string
{key: NAME, value: "env:MY_VAR"} environment variable MY_VAR, read on each request; "" if unset
{key: MY_VAR} shorthand for {key: MY_VAR, value: "env:MY_VAR"} (cookie name = variable name)

If an injected cookie has the same name as a forwarded client cookie, the injected value wins.

Database routes

For database routes the filtered set (forwarded plus injected) is what SQL templates can use as {{cookies.<name>}}, and it's where authentication looks for its token. A cookie that isn't listed (and isn't the auth key) isn't available to SQL. Values are bound parameters, like other request values. See Query Parameters.

cookies: [user_id]
routes:
  - route: my-activity
    sql: SELECT * FROM [[activity]] WHERE user_id = {{cookies.user_id}}

Remote routes: the Cookie header

The client's Cookie header is never forwarded as it is. API Dock writes the upstream Cookie header from the remote's cookies setting (the table above): the client cookies it names, plus injected ones. A remote with no cookies setting gets no cookies.

# remotes/config.yaml
remotes:
  core:
    url: https://api.example.org
    cookies: [__Secure-authjs.session-token]   # forward the user's login cookie only
    # cookies: true                            # or forward every client cookie

Changed in api_dock 0.10.0. Up to 0.9.1 the client's raw Cookie header was forwarded to every remote, so a remote without a cookies setting received all of the client's cookies, and cookies lists and injected cookies only took effect when the client sent no cookies. If a remote relied on that (for example an upstream that checks the user's session cookie), add cookies: [<cookie name>] or cookies: true to it when upgrading.

Authentication (database routes)

authentication:
  key: auth_token        # name of the cookie holding the token (required)
  value: "Z0FBQUFB..."   # exactly one source key (see table below)
  encrypted: true        # default: true
  encryption:            # optional: how to decrypt (default: local key file)
    method: local_key
    key_file: .api_dock_key
  failed_response:       # optional
    status: 403
    message: Valid token required

On each request to the database (including its root listing), API Dock reads the key cookie and compares it with the configured values:

  • Missing or wrong token: the response status is failed_response.status (default 401). The body is the whole failed_response mapping as JSON ({"status": 403, "message": "..."}), or {"error": "Authentication failed"} when it isn't set.
  • A provider or decryption error (bad key, unreachable secret store, invalid config) returns 500 {"error": "Authentication error"}.

encrypted defaults to true. A plain-text value, values or file must set encrypted: false. Otherwise API Dock tries to decrypt it and every request returns 500.

Token sources

Use exactly one of these keys. Two source keys in the same config is an error.

Key(s) Source Notes
value one token decrypted if encrypted
values list of tokens items may be strings or {value: ..., encrypted: false} to override per item
filepath text file, one token per line blank lines and # comments skipped; decrypted if encrypted
aws_secret_name (+ aws_region, default us-west-2) AWS Secrets Manager secret may be plain text, a JSON string, a JSON list, or a JSON object (its values are the tokens). encrypted is ignored
aws_tokens (+ optional aws_key_id, aws_region default us-west-2) list of AWS KMS ciphertexts each item is decrypted with KMS when the provider is built
aws_tokens_file (+ optional aws_key_id, aws_region) text file of AWS KMS ciphertexts, one per line blank lines and # comments skipped (works since 0.10.0)
gcp_project_id + gcp_secret_name (+ gcp_version, default latest) GCP Secret Manager same formats as AWS Secrets Manager. Needs pip install 'api-dock[gcp]' (or google-cloud-secret-manager)

Things to know:

  • The provider is built once per authentication config and reused. KMS tokens are decrypted then, and secret-manager secrets are fetched then and again whenever refresh_interval (seconds, default 300) has passed. A refresh that fails keeps the last values and logs a warning. Changing the config, or the modification time of a filepath / aws_tokens_file, builds a new provider. (Before 0.10.0 the provider was rebuilt on every request, so every request called the secret store or KMS and refresh_interval had no effect; aws_tokens_file was rejected.)
  • The cloud credentials need list permission (secretsmanager:ListSecrets, kms:ListKeys, or GCP secret listing), because the provider checks access when it is built.
  • Tokens are compared in constant time.
  • boto3 and cryptography are installed with API Dock. The GCP client isn't.

Decrypting values: encryption

encryption (inside authentication) says how value, values and filepath tokens are decrypted:

method Other keys Key comes from
local_key (default) key_file (default .api_dock_key) the key file. Only when key_file isn't set and .api_dock_key doesn't exist is the API_DOCK_ENCRYPTION_KEY environment variable used; a key_file you set must exist (since 0.10.0; before, a missing file silently fell back to the variable)
env_key key_env (default API_DOCK_ENCRYPTION_KEY) that environment variable only
aws_kms key_id, region (default us-east-1) AWS KMS
gcp_secrets project_id the configured value is treated as a secret name and its latest version is fetched

Relative key_file paths are resolved from the server's working directory. In a container, setting API_DOCK_ENCRYPTION_KEY is usually simpler than shipping a key file.

Encryption commands

api-dock generate-key                    # writes .api_dock_key (mode 600); --output PATH, --force
api-dock encrypt "secret123"             # prints: Encrypted value: Z0FBQUFB...
api-dock decrypt "Z0FBQUFB..."           # prints: Decrypted value: secret123

encrypt and decrypt take the same options:

Option Default Used by
--method, -m local_key local_key, env_key, aws_kms
--key-file .api_dock_key local_key
--key-env API_DOCK_ENCRYPTION_KEY env_key
--key-id none (required) aws_kms
--region us-east-1 aws_kms

Paste the printed value into the config. With KMS, decryption uses the region in your config (aws_region for aws_tokens defaults to us-west-2, while encryption.region defaults to us-east-1). Keep it the same as the region you encrypted with.

Example with a key from the environment:

api-dock generate-key --output /tmp/dock.key
export API_DOCK_ENCRYPTION_KEY=$(cat /tmp/dock.key)
api-dock encrypt --method env_key "secret123"
authentication:
  key: auth_token
  value: "Z0FBQUFB..."
  encryption: {method: env_key}

Clone this wiki locally