402 Payment Required with payment options (for x402) or 401 Unauthorized with a WWW-Authenticate challenge (for OAuth discovery).
API keys (developers)
Pass your key in theAuthorization header:
Key format
| Environment | Prefix | Example |
|---|---|---|
| Production | bsk_live_ | bsk_live_a1B2c3D4... |
| Test | bsk_test_ | bsk_test_x9Y8z7W6... |
Key management
| Operation | Endpoint | Method |
|---|---|---|
| Create key | /api/v1/api-keys | POST |
| List keys | /api/v1/api-keys | GET |
| Get key | /api/v1/api-keys/{id} | GET |
| Rotate key | /api/v1/api-keys/{id}/rotate | POST |
| Revoke key | /api/v1/api-keys/{id} | DELETE |
Key rotation
Rotate a key to get a new secret while preserving the key’s metadata, scopes, and audit trail. The old key is immediately revoked and a new one is returned.Scopes
Keys can be scoped to limit access. A key withnull scopes has full access. Scoped keys use the format domain:action:
403 Forbidden.
Key security
- Keys are hashed with Argon2id (memory-hard) before storage, with a server-side pepper on the deterministic lookup index. The raw key is never persisted.
- Keys are shown once at creation. They cannot be retrieved again.
- Revoked keys are immediately unusable.
- Key usage is tracked via
last_used_at. - All key operations are recorded in the audit log.
Keycloak OIDC (OAuth clients)
Claude.ai’s custom-connector UI, and any other OAuth 2.1 MCP client, authenticates through Keycloak atauth.builddaddy.app/realms/worktruck. You don’t set up an OAuth client yourself — Claude.ai uses RFC 7591 Dynamic Client Registration to register with Keycloak on first use, runs the PKCE authorization-code flow in a browser popup, and presents the resulting JWT on every MCP request.
From your side, the flow is:
- Paste
https://mcp.worktruck.app/mcp/v1into Claude.ai’s custom connector URL field. - Claude.ai’s first request to the server returns
401 Unauthorizedwith aWWW-Authenticate: Bearer resource_metadata="..."header pointing at/.well-known/oauth-protected-resource. - Claude.ai fetches that document, discovers Keycloak as the authorization server, registers itself, and redirects you to Keycloak login.
- After you sign in, Keycloak issues a JWT with
aud=mcp(oraud=https://mcp.worktruck.app/mcp/v1under RFC 8707 resource binding). Claude.ai presents it on subsequent MCP requests.
sub claim to your Worktruck tenant and member via the internal idp_users table (JIT-provisioning a new tenant on first ever login), and enforces Mcp-Protocol-Version: 2025-06-18 on every non-initialize JWT-authenticated request.
Tokens carry the mcp:tools scope. Domain-level access (contacts:read vs. tasks:write, etc.) is enforced by your member’s access policies, not by token scopes.
x402 payments (agents)
AI agents can pay per-request with USDC on Base. No account, no API key required. Pass the x402 payment receipt in thePAYMENT-SIGNATURE header:
Error responses
| Status | Meaning |
|---|---|
401 Unauthorized | Invalid, expired, or revoked API key; invalid/expired JWT; missing Mcp-Protocol-Version on JWT-authenticated MCP request. Response includes WWW-Authenticate header for OAuth discovery |
402 Payment Required | No credentials provided — includes payment options in response |
403 Forbidden | Valid key/token, but missing required scope or member access |
