SPB Git forge

spb/doc-api

Public
2commits 1branches 0releases
15.7 MBsize
maindefault branch
13 days agolast push
Python 88.3% TypeScript 7.6% Shell 4.1%
12.1 KB

# API key handling

Status: DOCUMENTED (xAI GET /v1/api-key and the 400-on-bad-key behaviour LIVE_VERIFIED 2026-09-19; Gemini header auth LIVE_VERIFIED, ?key= never used) Sources: https://developers.openai.com/api/docs/guides/production-best-practices#api-keys · https://developers.openai.com/api/docs/guides/error-codes (401 "IP not authorized", "Incorrect API key") · https://developers.openai.com/api/docs/guides/safety-best-practices#revoke-compromised-api-keys · https://platform.claude.com/docs/en/api/errors (401 authentication_error, key expiration) · https://platform.claude.com/docs/en/api/admin (API key scope) · https://platform.claude.com/docs/en/api/rate-limits · xAI: https://docs.x.ai/developers/management-api-guide (create keys with acls[], qps/qpm/tpm, expireTime; rotate with oldSecretExpireTime; propagation), https://docs.x.ai/developers/rest-api-reference/inference/other (GET /v1/api-key, GET /v1/me), https://docs.x.ai/developers/debugging (400 invalid-argument "Incorrect API key provided"), https://docs.x.ai/developers/faq/security (mTLS host, ZDR), https://docs.x.ai/developers/advanced-api-usage/mtls · Gemini: https://ai.google.dev/gemini-api/docs/api-key (x-goog-api-key, standard vs authorization keys, "Restricting and securing your keys", unrestricted keys rejected, leaked keys blocked), https://ai.google.dev/gemini-api/docs/oauth, https://ai.google.dev/gemini-api/docs/ephemeral-tokens, https://ai.google.dev/gemini-api/terms (Unpaid Services data use), https://ai.google.dev/gemini-api/docs/usage-policies · this repo's CLAUDE.md + scripts/live.py Last verified: 2026-09-19

# Key types you will meet

OpenAI Anthropic xAI Gemini
Runtime key Project API key (sk-proj-…), user- or service-account-owned; Authorization: Bearer Workspace API key (sk-ant-api…), scope organization or workspace; x-api-key + anthropic-version Team API key (xai-…) created in the console or via the Management API; Authorization: Bearer on REST, WebSocket and gRPC; no API version or beta headers. Keys carry ACLs (api-key:endpoint:* / api-key:endpoint:chat, api-key:model:* / api-key:model:grok-4.6) — a key created via the API has no access by default — plus optional per-key qps/qpm/tpm caps and expireTime; can be disabled/blocked; the whole team can be blocked AI Studio API key (AIza…); x-goog-api-key header (recommended, used by the SDKs and this atlas). ?key= in the URL also works but leaks into proxy/CDN/referrer logs — never use it. Standard keys identify a project only; authorization (auth) keys are bound to a Google Cloud service account (granular IAM, fast leaked-key enforcement) and are the default since 2026-05-28; unrestricted standard keys are already rejected, standard keys are rejected from September 2026 — migrate. OAuth 2.0 / ADC (Authorization: Bearer <token>) for owner-scoped resources; ephemeral tokens (POST /v1beta/auth_tokens) for browser Live-API clients. The OpenAI-compat layer (/v1beta/openai/*) needs the key as Authorization: Bearer instead
Admin / management key Admin API key for /v1/organization/* Admin API key for /v1/organizations/* with read:* / write:* scopes Management key (console → Settings → Management Keys; SCOPE_TEAM or SCOPE_ORGANIZATION; requires "Management Keys Read + Write") for https://management-api.x.ai — a different host and key type; an inference key there → 401 {"code": 16, "message": "Invalid bearer token…"}. This atlas has none (ACCOUNT_RESTRICTED) Google Cloud IAM on the project (apikeys.keys.*, iam.serviceAccounts.*, serviceusage.services.enable) and Cloud Billing; no separate "admin API" — the Gemini API only exposes /v1/webhooks, agents, credentials, triggers under the same key
Introspection Usage page Console GET /v1/api-key → redacted_api_key, name, user_id, team_id, acls[], api_key_blocked, api_key_disabled, team_blocked, create_time (live: acls ["api-key:model:*","api-key:endpoint:*"]); GET /v1/me → zdr_status (no_zdr / zdr), team, key flags (API key or OAuth). Management: GET /auth/management-keys/validation, GET /auth/api-keys/{id}/propagation none for the key itself; AI Studio shows keys (100 keys / 50 projects displayed; keys restricted to other APIs are hidden). The 429 body's quotaDimensions.model and the X-Gemini-Service-Tier header tell you which tier/model the key hit
Bad-key behaviour 401 "Incorrect API key" 401 authentication_error 400 invalid-argument "Incorrect API key provided. You can obtain an API key from https://console.x.ai." (missing header → 401 unauthenticated:no-credentials; missing ACL → 403) — a client that only treats 401 as "fix credentials" will misclassify this 400 INVALID_ARGUMENT "API key not valid. Please pass a valid API key." or 403 PERMISSION_DENIED; leaked key → 403 "Your API key was reported as leaked. Please use another API key." (auto-blocked by Google's scanners)
Governance API Key Governance (service-account-only, max lifetime), IP allowlist Workspaces, key expiration, anthropic-workspace-id header ACL scoping per key, per-key rate caps, expireTime, rotation with overlap (POST /auth/api-keys/{id}/rotate, oldSecretExpireTime default 24 h, max 7 d), team-level mTLS (https://mtls.api.x.ai: client certificate in addition to the key), regional hosts (us.api.x.ai), team-wide Zero Data Retention Cloud-console API restrictions (restrict the key to the Generative Language API only) and application restrictions (IP addresses, HTTP referrers, Android/iOS apps); auth keys inherit the service account's IAM; leaked-key auto-blocking; 10 projects creatable from AI Studio
Tracking Usage page per key Console per workspace/key console Usage Explorer (by key, model, request IP, cluster, token type) and POST /v1/billing/teams/{id}/usage (Management API); per-request usage.cost_in_usd_ticks; x-request-id AI Studio rate-limit/usage dashboards (per project, not per key); Cloud Billing reports; body responseId (no request-id header)

# Rules

  1. Never in code, repos, images, client bundles, or prompts. Environment variables or a secret manager only. This atlas keeps keys in .env (mode 600, gitignored) and injects them through scripts/live.py / scripts/lib.sh, which also mask sk-… patterns and auth headers in anything saved (mask()).
  2. One key per deployment/environment. OpenAI: separate staging and production projects; Anthropic: separate workspaces. A leaked staging key must not reach production data or budgets.
  3. Service-account keys for servers, not personal keys: they survive employee departures and can be governed (OpenAI API Key Governance can enforce this).
  4. Set an expiry at creation and rotate on a schedule: create the replacement → deploy → verify → revoke the old one (OpenAI's documented sequence). Enforce a maximum lifetime org-wide so forgotten keys die.
  5. Restrict network origin where possible: OpenAI IP allowlist (org/project). Anthropic: pin egress from your servers and monitor anthropic-organization-id/anthropic-workspace-id in responses to detect misrouted keys.
  6. Never send a runtime key to the browser or mobile app. Proxy through your backend; the backend adds safety_identifier (OpenAI) / metadata.user_id (Anthropic) so abuse is attributable per end-user, not per key.
  7. Admin keys are not runtime keys: they cannot call inference (Anthropic Admin API keys are org-management only) and must live in a separate, more restricted secret with GET/LIST-only automation (this repo's rule: never destructive Admin actions).
  8. On compromise: revoke immediately (OpenAI safety-best-practices "Revoke compromised API keys"), rotate, review usage pages and audit logs (GET /v1/organization/audit_logs; xAI GET /audit/teams/{id}/events + Usage Explorer by request IP; Gemini Cloud audit logs) for the exposure window, and check spend limits were not raised. xAI's rotate endpoint keeps the old secret valid for up to 7 days — set oldSecretExpireTime short once the new key is deployed. Gemini blocks keys it finds leaked on its own ("reported as leaked") — treat that 403 as an incident, not a bug.
  9. Detect leaks pre-commit: scan for sk-, sk-ant-, sk-proj-, sk-admin-, whsec_, xai-, AIza (Google API keys), AQ. (Gemini auth-key/ephemeral-token style) patterns and ?key= query strings (the mask regexes in scripts/live.py cover all of these) and use platform secret scanning.
  10. Timeouts + retries must not amplify a bad key: 401/403 are never retried, and neither is xAI's 400 invalid-argument nor Gemini's 400/403 key errors (see docs/architecture/resilience.md) — a retry storm on an invalid key is noise that hides real problems.
  11. xAI: scope keys with ACLs, not just with limits. api-key:endpoint:chat + api-key:model:grok-4.3 for a chat-only service; grant image/* only where needed; add qpm/tpm caps per key so a leaked key cannot drain the team's TPM; introspect with GET /v1/api-key in your health check and alert on api_key_blocked / team_blocked. Inference keys and Management keys live in different secrets; the Management key can mint inference keys, so it is the more sensitive one.
  12. Gemini: restrict every key in the Cloud console (API restriction → Generative Language API; application restriction → your server IPs) and prefer auth keys bound to a dedicated service account with only the Generative Language roles. Never embed a key in a mobile/web client — use ephemeral tokens for the Live API and your backend for everything else. Note that the x-goog-api-key header is stripped by fewer intermediaries than a ?key= parameter, but any proxy that logs headers still sees it: TLS end-to-end, no header logging.
  13. Gemini free tier is a data-use decision, not just a quota. Under the Gemini API Terms, Unpaid Services (free tier, AI Studio) let Google use prompts, uploaded content and responses "to provide, improve, and develop Google products", with human review — do not send confidential or personal data through a free-tier key. Paid Services are not used for product improvement but are logged for abuse monitoring for a limited period (usage policies: 55 days). EEA/UK/CH end users must be served with Paid Services only. Enable billing (a Cloud Billing account also lifts limit: 0 429s on Pro models) before any production or privacy-sensitive traffic; for a contractual zero-data-retention posture use Vertex AI.

# Checklist

  • Keys only in secret manager / .env (600); .env in .gitignore; .env.example has placeholders only.
  • Separate keys per environment; project (OpenAI) / workspace (Anthropic) / team + ACL-scoped key (xAI) / Cloud project + restricted auth key (Gemini) per app.
  • Service-account keys with expiry (OpenAI governance, Anthropic expiration, xAI expireTime, Gemini auth keys); org-level max lifetime where available.
  • Network restrictions: OpenAI IP allowlist; Gemini application restrictions (IP); xAI mTLS for enterprise teams.
  • Rotation runbook written and rehearsed (xAI: rotate with overlap then expire the old secret; Gemini: create → restrict → deploy → delete); revocation path tested.
  • Admin / Management keys separate, read-only in automation, never on app servers; xAI Management key stored apart from inference keys.
  • Logs masked (Authorization, x-api-key, x-goog-api-key, sk-…, xai-…, AIza…, ?key=), request bodies not logged verbatim; Gemini never called with ?key=.
  • End-user attribution (safety_identifier OpenAI/xAI, metadata.user_id Anthropic, labels.safety_identifier Gemini) so a bad actor is blocked without rotating the shared key.
  • Gemini: billing enabled and the free-tier data-use terms understood before sending anything sensitive; Cloud-console key restrictions applied.
  • Clients classify xAI 400 "Incorrect API key" and Gemini 400/403 key errors as credential failures (no retry, alert).