Repository navigation
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'scookiessetting 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 anauthenticationblock that remote routes ignore.
| 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.
| 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"| 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.
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}}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 cookieChanged in api_dock 0.10.0. Up to 0.9.1 the client's raw
Cookieheader was forwarded to every remote, so a remote without acookiessetting received all of the client's cookies, andcookieslists 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), addcookies: [<cookie name>]orcookies: trueto it when upgrading.
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 requiredOn 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(default401). The body is the wholefailed_responsemapping 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.
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 afilepath/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 andrefresh_intervalhad no effect;aws_tokens_filewas 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.
-
boto3andcryptographyare installed with API Dock. The GCP client isn't.
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.
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: secret123encrypt 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}Getting started
Remote APIs
Databases
- SQL Database Support
- Query Parameters
- Conditional SQL
- Shared Database Config
- Cross-Schema Queries
- PostgreSQL
- Lookups
Serving
Developing