Skip to main content
Two API-key credential families exist for callers outside Praxa’s own first-party apps. aura_agent_* keys are live today, each scoped to one published custom-agent deployment. praxa_sk_ keys are the tenant-wide credential for the Praxa Execution Fabric (/v1/execute and the rest of the /v1/* gateway) and are a developer preview.
Status: aura_agent_* deployment keys and embed origin-allowlists — Available today. praxa_sk_ tenant keys, scopes, and the key console — Developer preview.
aura_agent_* keys are not being retired. Per the fabric design’s resolved decisions, aura_agent_* “stays valid for custom-agent deployments and migrates onto the tenant model later” — you do not need to pre-emptively rotate onto praxa_sk_ when it ships (design spec §7.2). For what a key’s scope actually constrains, see scopes-and-tenancy.md. For throttling behavior, see rate-limits.md.

Key formats

These three are the only principal kinds the platform recognizes on authenticated surfaces. All three resolve through one server-side principal resolver to the same fail-closed, server-derived authority model — the credential changes, the authorization logic doesn’t (design spec §3.2).

aura_agent_* — deployment credential

  • Shape: aura_agent_ followed by 64 lowercase hex characters (32 random bytes from crypto.getRandomValues).
  • What it can do: authenticates one deployment’s External API channel only. It has no separate scope list — the key is the deployment’s identity, so its authority is exactly that deployment’s bound connectors, knowledge, and memory (docs/custom-agents.md).
  • Companion control: a deployment on the website-embed channel is additionally bound to an explicit origin allowlist, checked at both token exchange and run time — see scopes-and-tenancy.md for the full mechanism.
  • Recognition on the wire: Authorization: Bearer aura_agent_<64 hex>. The server distinguishes “not an Aura key” from “an Aura key that’s malformed” — a value that starts with aura_agent_ but doesn’t match the full 64-hex-character shape is still flagged, so the route fails closed instead of silently treating it as anonymous (src/lib/custom-agents/api-auth.server.ts).

praxa_sk_ — tenant credential (developer preview)

  • Shape: praxa_sk_ followed by a hex string. The prefix itself is a locked owner decision (2026-07-30); the exact byte length isn’t finalized in the design spec yet.
  • What it can do: scoped by the key, not implicit like aura_agent_*. Each key carries scopes, an expiry, a per-key rate-limit tier, and a last-used timestamp, managed through a key CRUD console (design spec §3.2).
  • Endpoint family: the public gateway’s /v1/* routes (execute, runs, runs/:id/events, runs/:id/approve, runs/:id/cancel, usage, webhooks), served at api.praxa.io — already a live custom domain on the router worker, but the /v1/* dispatch to the gateway is flag-gated and not turned on yet (design spec §3.1, §4 F1). This is a different path from the existing /api/v1/* desktop gateway, which is Supabase-JWT-only and unrelated to API keys.
  • As of this writing, no endpoint serves this contract in production yet — the request/event/error schemas exist in packages/ai-platform but are not wired to a live route (docs/ai-platform/README.md §7).

Lifecycle

Create

  • aura_agent_*: minted server-side when a deployment’s External API channel is created. 32 random bytes become aura_agent_<hex> (createAgentPublishableKey(), src/lib/custom-agents/embed-token.server.ts). The plaintext is returned exactly once, in that creation response.
  • praxa_sk_ (preview): issued from the tenant’s key console (design spec §3.2, §4 F2). Not built yet.

Rotate

  • aura_agent_*: the rotate_deployment_secret (External API channel) and rotate_embed_secret (website channel) mutations call Postgres RPCs that generate a fresh secret server-side, store its hash, and return the new plaintext exactly once in that mutation’s response (src/lib/custom-agents/repository.server.ts). The old key stops verifying immediately: “Secret rotation invalidates the old credential for future exchanges” (docs/custom-agents.md, “Lifecycle and versions”). Plan for a hard cutover, not a shared grace window.
  • praxa_sk_ (preview): the design spec names key CRUD and revocation explicitly but does not name a dedicated rotate operation the way aura_agent_* has one. Until/unless one ships, treat rotation as create-new-then-revoke-old through the console — that’s an operational reading of the CRUD surface, not a documented endpoint.

Revoke

  • aura_agent_*: revocation is deployment-level, not a standalone key-revoke call, because the key is the deployment credential. Deployments have their own active, paused, and revoked states; pausing blocks new execution without destroying audit history, and revoking is the permanent form (docs/custom-agents.md).
  • praxa_sk_ (preview): revocation is a named, per-key field/operation — independent keys on the same tenant can be revoked individually (design spec §3.2).

Expire

  • aura_agent_*: no built-in expiry on the deployment credential itself. It’s valid until rotated or the deployment is paused/revoked. (Don’t confuse this with the website-embed visitor token exchanged for it — that token is short-lived and carries its own token_ttl_seconds, but it’s a different, downstream credential.)
  • praxa_sk_ (preview): an explicit expiry field, with last-used tracked separately (design spec §3.2).

Storage promises

  • Hashed at rest, never stored or logged in plaintext. For aura_agent_*: a SHA-256 digest, hex-encoded, verified with a constant-time comparison (hashAgentPublishableKey, verifyAgentPublishableKey, src/lib/custom-agents/embed-token.server.ts) — the same digest Postgres computes via pgcrypto, so there’s one credential authority, not two drifting implementations. For praxa_sk_: the design spec commits to “hash-at-rest” without naming an algorithm. The aura_agent_* SHA-256-plus-constant-time-compare implementation is the likely template but isn’t confirmed for platform_api_keys yet.
  • Shown once. The plaintext key comes back in the create/rotate response body and never again — not on a later read, not in the console, not in logs. Losing it means rotating or issuing a new one, not recovering it.
  • Never in logs or error responses. Server logs and errors carry stable codes and correlation IDs, not provider payloads or secrets (docs/decisions/2026-07-24-ai-platform-extraction.md, “Security model”).

Best practices

  • Environment variables or a secrets manager — never source control, a mobile/web app bundle, or client-side JavaScript. Both key families are bearer secrets: whoever holds one can act as that deployment (aura_agent_*) or that tenant (praxa_sk_). Anything that ships to a browser or device is readable by whoever has the browser or device.
  • Never hand a key to a browser or native client directly. Exchange it for a short-lived, origin-bound token server-side instead. The website embed channel already works this way: the long-lived credential is exchanged for a short-lived visitor token bound to deployment, origin, and session (docs/custom-agents.md, “Runtime channels”) — mirror that pattern for anything you build on top of these keys.
  • Rotate on a schedule, and immediately after any suspected exposure — a key committed to a repo, a leaked log line, an offboarded integration. Rotation invalidates the old key immediately, so coordinate the cutover rather than assuming overlap.
  • Least privilege. For praxa_sk_, request only the scopes an integration needs (see scopes-and-tenancy.md). For aura_agent_*, which has no scope list to narrow, the equivalent discipline is one key per deployment per integration — don’t share a single deployment’s key across unrelated systems just because it’s convenient.
  • One key per system. Distinct keys per integration let you revoke one caller without rotating every other one that happens to share a key.

Examples

aura_agent_* — calling a deployment’s External API today

praxa_sk_ — Execution Fabric (developer preview, illustrative)

Not live yet. Field names below follow the design spec’s /v1/execute parameter list (task, context, tools, policy, delivery, plus an Idempotency-Key header) — the JSON Schema itself is not yet published, so treat the nesting as illustrative rather than a contract.

See also

  • scopes-and-tenancy.md — the tenant model and what a scope constrains.
  • rate-limits.md — per-key throttling, 429/503 handling, retry guidance.