BYOK (Bring Your Own Keys) User Guide¶
BYOK lets multi-user deployments store per-user provider keys, with optional org/team shared keys, while keeping server defaults available as a fallback.
Requirements¶
AUTH_MODE=multi_user.BYOK_ENABLED=true.BYOK_ENCRYPTION_KEYset (base64-encoded 32-byte key).- Optional:
BYOK_ALLOWED_PROVIDERSallowlist (comma-separated). - Optional:
BYOK_ALLOWED_BASE_URL_PROVIDERSallowlist for BYOKbase_urloverrides. - Optional:
BYOK_LAST_USED_THROTTLE_SECONDS(default300) to throttle runtimelast_used_atupdates.
Example key generation:
python -c "import base64, os; print(base64.b64encode(os.urandom(32)).decode())"
OpenAI OAuth First-Time Setup¶
For the first-time OpenAI account-linking flow (operator prerequisites + user walkthrough), see:
Anthropic + Claude Code/SDK Setup¶
For Anthropic setup with Claude Code/Claude SDK and current support limits (API-key based today, no Anthropic OAuth BYOK flow yet), see:
Provider Allowlist¶
BYOK respects an allowlist at both write time and runtime:
- If a provider is not allowlisted, new BYOK keys are rejected and stored keys are ignored at runtime.
- Server default keys still apply when BYOK is disallowed.
/api/v1/users/keysshows stored-but-disallowed providers assource=disabled.
Default allowlist (commercial providers):
anthropic, bedrock, cohere, custom-openai-api, custom-openai-api-2, deepseek,
elevenlabs, google, groq, huggingface, mistral, moonshot, openai, openrouter,
qwen, voyage, zai
Credential Resolution Order¶
Resolution is per request and normalized to lower-case provider names:
- User BYOK key
- Team shared key (if any)
- Org shared key (if any)
- Server default key (from
.envorConfig_Files/config.txt)
If the provider requires auth and no key resolves, the API returns:
{
"error_code": "missing_provider_credentials",
"message": "Provider '<name>' requires an API key."
}
Credential Fields¶
Credential fields are validated per provider. By default, unknown providers only
allow org_id and project_id, and base_url is only allowed for providers
listed in BYOK_ALLOWED_BASE_URL_PROVIDERS and when the caller is a trusted
principal (admin/service).
Notes:
- Empty strings are rejected.
- Allowed fields must be provided explicitly; they are not inherited from server defaults.
base_urloverrides the providerapi_base_urlwhen permitted.org_id/project_idare applied when notnull.- Unsupported fields return
400.
User Endpoints¶
Create or update a key:
POST /api/v1/users/keys
Request:
{
"provider": "openai",
"api_key": "sk-...",
"credential_fields": { "base_url": "https://api.openai.com/v1" },
"metadata": { "label": "personal" }
}
Response:
{
"provider": "openai",
"status": "stored",
"key_hint": "1234",
"updated_at": "2025-01-01T00:00:00Z"
}
List key status:
GET /api/v1/users/keys
Response item fields:
source:user | team | org | server_default | none | disabledhas_key:trueif the user stored a key
Test a key:
POST /api/v1/users/keys/test
Delete a key:
DELETE /api/v1/users/keys/{provider}
Org/Team Shared Keys (Manager Role)¶
Org/team owners, admins, and leads can manage shared keys. Global admins are allowed.
Org endpoints:
POST /api/v1/orgs/{org_id}/keys/shared
GET /api/v1/orgs/{org_id}/keys/shared
POST /api/v1/orgs/{org_id}/keys/shared/test
DELETE /api/v1/orgs/{org_id}/keys/shared/{provider}
Team endpoints:
POST /api/v1/teams/{team_id}/keys/shared
GET /api/v1/teams/{team_id}/keys/shared
POST /api/v1/teams/{team_id}/keys/shared/test
DELETE /api/v1/teams/{team_id}/keys/shared/{provider}
Shared keys apply to all members in that org/team and show as source=shared in user listings.
Admin Endpoints¶
Admins can list and revoke user keys, and manage shared keys across org/team scopes:
GET /api/v1/admin/keys/users/{user_id}
DELETE /api/v1/admin/keys/users/{user_id}/{provider}
POST /api/v1/admin/keys/shared
GET /api/v1/admin/keys/shared
POST /api/v1/admin/keys/shared/test
DELETE /api/v1/admin/keys/shared/{scope_type}/{scope_id}/{provider}
Auditing and Updates¶
last_used_atupdates on successful provider calls.- Runtime updates are throttled by
BYOK_LAST_USED_THROTTLE_SECONDS. keys/testendpoints updatelast_used_atonly if the tested key matches the stored key.- Responses never include plaintext keys;
key_hintshows the last 4 characters only.
Key Rotation¶
Rotate BYOK encryption keys using the maintenance helper:
- Set
BYOK_ENCRYPTION_KEYto the new primary key. - Set
BYOK_SECONDARY_ENCRYPTION_KEYto the old key. - Run the rotation helper (dry-run first recommended):
python -m Helper_Scripts.AuthNZ.rotate_byok_keys --dry-run
python -m Helper_Scripts.AuthNZ.rotate_byok_keys
After a successful run, remove BYOK_SECONDARY_ENCRYPTION_KEY to enforce the new key.
Error Codes¶
400invalid payloads.503missing provider credentials (error_code=missing_provider_credentials).403BYOK disabled or provider disallowed.404deleting a key that does not exist.401/403for/keys/testwhen provider rejects credentials.502for provider test-call failures.
Metrics (Local-Only by Default)¶
Metrics appear in /metrics and /api/v1/metrics when metrics are enabled:
byok_resolution_total- Labels:
provider,source,allowlisted,byok_enabled byok_missing_credentials_total- Labels:
provider,operation,allowlisted,byok_enabled
Metrics are local-only unless you configure external exporters.