Skip to content
Beta — Truss is in public beta. Documentation is actively updated but may not reflect the latest changes. Report issues on GitHub.

API Keys

Truss uses API keys to authenticate client API requests. Every /v1/* endpoint requires a key passed via the apikey header (or x-api-key).

TypePrefixRLS behaviorUse case
anontruss_pk_Respects RLS policiesClient-side apps, public-facing
service_roletruss_sk_Bypasses RLS (runs as postgres role)Server-side, admin scripts, CLI

Anon keys are safe to expose in client-side code. They respect PostgreSQL Row-Level Security (RLS) policies, so users can only access data their policies allow.

When a request uses an anon key with a JWT in the Authorization header, Truss:

  1. Decodes the JWT payload
  2. Sets request.jwt.claims and request.jwt.sub as Postgres session config
  3. Switches to the authenticated role

Service role keys bypass RLS entirely and run queries as the postgres role. Never expose these in client-side code. Use them for:

  • Server-side API calls
  • Admin scripts and migrations
  • Management API endpoints (which require service_role)
  • CI/CD pipelines

Navigate to Settings > API Keys and click “Create Key”. Choose the type and give it a label.

Terminal window
curl -X POST http://localhost:8787/api/keys \
-H "Content-Type: application/json" \
-d '{"keyType": "service_role", "label": "backend-server"}'

Response:

{
"key": {
"id": 1,
"key_type": "service_role",
"key_prefix": "truss_sk_abc",
"label": "backend-server",
"created_at": "2025-01-15T10:00:00Z"
},
"secret": "truss_sk_abcdefghij..."
}

The secret is only returned once at creation time. Store it securely.

Pass the key via the apikey header:

Terminal window
curl http://localhost:8787/v1/db/users \
-H "apikey: truss_pk_your_anon_key"
const res = await fetch('http://localhost:8787/v1/db/users', {
headers: { apikey: 'truss_pk_your_anon_key' }
});

The x-api-key header also works as an alias.

Terminal window
curl -X DELETE http://localhost:8787/api/keys/{id}

Revoked keys immediately stop working. The key row is kept for audit purposes but marked as revoked.

Rate limiting is opt-in per API key. In the open-source core there is no default limit — keys are unlimited unless you set a per-key rate_limit (requests/minute) on the key. The limit headers are returned on every response; when a key is unlimited they report -1:

X-RateLimit-Limit: -1
X-RateLimit-Remaining: -1

When a per-key limit is configured, the headers report that limit and the remaining count in the current 60-second window, and the API returns 429 Too Many Requests once it is exceeded.

  • Keys are stored as SHA-256 hashes — the raw key is never stored
  • Each key tracks last_used_at for auditing
  • Revoked keys are rejected immediately
  • Rate limiting is per-key, in-memory, with a 60-second sliding window

To rotate a key without downtime:

  1. Create a new key with the same type (anon or service_role)
  2. Update your application to use the new key
  3. Verify the new key works in production
  4. Revoke the old key once all clients have migrated
Terminal window
# 1. Create new key
curl -X POST http://localhost:8787/api/keys \
-H "Content-Type: application/json" \
-d '{"keyType": "service_role", "label": "backend-v2"}'
# 2. Update your app's environment variable with the new key
# 3. Revoke old key
curl -X DELETE http://localhost:8787/api/keys/{old_key_id}

There is no automatic rotation schedule — rotation is a manual operation. The last_used_at timestamp on each key helps you verify whether the old key is still in use before revoking it.

All /v1/* endpoints require an API key. Pass it via the apikey header (or x-api-key).

Terminal window
# Read (anon key is fine if RLS allows it)
curl http://localhost:8787/v1/db/posts \
-H "apikey: truss_pk_your_anon_key"
# Write (service_role key bypasses RLS)
curl -X POST http://localhost:8787/v1/db/posts \
-H "apikey: truss_sk_your_key" \
-H "Content-Type: application/json" \
-d '{"title": "Hello", "body": "World"}'
Terminal window
curl -X POST http://localhost:8787/v1/sql \
-H "apikey: truss_sk_your_key" \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT count(*) FROM users"}'

When using an anon key with a JWT, include the token in the Authorization header. Truss extracts the claims and passes them to Postgres for RLS evaluation.

const res = await fetch('http://localhost:8787/v1/db/messages', {
headers: {
'apikey': 'truss_pk_your_anon_key',
'Authorization': `Bearer ${userJwt}`
}
});

Management endpoints (/v1/status, /v1/database/schema, /v1/webhooks, etc.) require a service_role key:

Terminal window
curl http://localhost:8787/v1/status \
-H "apikey: truss_sk_your_key"
curl http://localhost:8787/v1/database/schema \
-H "apikey: truss_sk_your_key"

The management API endpoints (/v1/status, /v1/keys, /v1/database/schema, etc.) require a service_role key. Attempting to access them with an anon key returns 403 Forbidden.