auth

three keys,
one network.

tiredapi separates auth by plane. Each plane uses one mechanism. We do not chain them, we do not fall back. Pick the right key for the right call.

REST · bearer

api.tired.events accepts a bearer token in the Authorization header. Two issuers, same shape.

session token

HS256 JWT

Issued by /auth/login, /auth/cognito/login, passkey, magic-link, and OAuth flows. Stored in SESSION_TOKENS KV with TTL. Revocable by JTI. Good for ~24h, scoped to one user.

jti reverse-indexed for revocation
api key

opaque + hashed

Issued from the organizer dashboard at /studio/api-keys. SHA-256 hashed at rest. Long-lived. Rotate by issuing-then-deleting. Use this in production deploys.

api_keys.hash, SHA-256, never readable
cross-domain JWT

HS256 single-use

For cross-domain handoffs (tired.events ↔ tiredevents.com), /v1/token/issue mints a one-use token. /v1/token/verify validates and writes the JTI to cross_site_nonces for replay defense.

JTI uniqueness enforces single-use
# typical REST call
curl https://api.tired.events/events \
  -H "Authorization: Bearer $TIRED_TOKEN"

MCP · bearer

mcp.tiredapi.co accepts a separate bearer. Dual-mode: a static token, or a tiredapi.co session JWT validated against KV with a 60s cache (fail-closed).

# typical MCP call
curl -X POST https://mcp.tiredapi.co/mcp \
  -H "Authorization: Bearer $MCP_BEARER" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

Every tool call is audit-logged. Sensitive keys in args (anything matching /secret|token|password|key/i) are redacted before persistence — you can audit who called what without leaking what they passed in.

TOTP · the gate

Admin and payout-altering routes require a TOTP confirmation at /auth/totp/complete within the request. RFC 6238 — Google Authenticator, 1Password, anything compatible.

# step 1 — receive the totp_required: true response
curl -X POST https://api.tired.events/payouts/release \
  -H "Authorization: Bearer $TIRED_TOKEN" \
  -d '{"payout_id":"po_…"}'
# → 401 {"error":"totp_required","challenge":"ch_…"}

# step 2 — confirm with the 6-digit code
curl -X POST https://api.tired.events/auth/totp/complete \
  -H "Authorization: Bearer $TIRED_TOKEN" \
  -d '{"challenge":"ch_…","code":"123456"}'

the don'ts.

A short list, because the long list is in the audit log.