Authentication
Two credential types, distinguished by prefix and routed accordingly.
The gateway is dual-mode. It decides how to authenticate a request from the prefix of the bearer token.
Project API keys (tr_sk_…)
For machines — SDKs, AI tools, your application code.
- Shape:
tr_sk_followed by random hex. - Storage: only a BLAKE3 hash is stored (in
project_api_keys), plus a short prefix for display. The plaintext is shown once, at creation. - Resolution: the gateway hashes the presented key, looks it up, and — if it
exists and isn't revoked — resolves the owning project. It then injects
the engine's internal key and proxies to that project's daemon. Your
tr_sk_…never reaches the engine.
Create and revoke keys in the API Keys tab, or via
POST / DELETE /v1/projects/{id}/keys.
curl "$GATEWAY/engine/api/v1/ws/$WS/health" \
-H "Authorization: Bearer tr_sk_…"Session JWTs
For humans — the Console.
- Issued by the identity service, verified with the shared
tr_common::authkeys. - Carry the user, optional org, tier, and scopes; checked for org membership before any project access.
- Used for the control-plane surfaces (keys, secrets, egress, identity, billing, provisioner).
The gateway never lets a Console session reach a project the user isn't a member of.
Engine-level auth (self-hosting)
When you run the engine yourself, root serve --api-key <key> enables bearer
auth on the engine directly (compared in constant time). In the cloud this key
is the per-project internal key the provisioner mints and the gateway injects —
you never see it. See Cloud vs Self-host.
Treat keys like passwords
A tr_sk_… key grants full access to its project. Store it in the
secrets vault or your own secret manager, never in
source control. Revoke immediately if leaked — revocation takes effect at once.
Rate limiting
The gateway rate-limits per principal (project + plan tier), backed by an in-memory token bucket or Redis when configured. Exceeding your tier's requests-per-minute returns a rate-limit error; upgrade the plan or slow down.