401, 403 or an auth-related 503. It covers the one header every protected route reads, the two kinds of credential that header can carry, how a key is checked, and each auth error with its fix.
The header
Every protected/v1 route takes one header:
- The scheme name is compared case-insensitively, so
Bearer,bearerandBEARERall work. - The scheme and the credential are split on the first whitespace, and the credential is trimmed.
- An empty credential counts as no credential.
- There is no other auth header and no cookie auth.
Two kinds of credential
The server decides what a credential is from its prefix.
Your code uses API keys. The console holds its own session when you sign in, and you never need to copy a session into code. Create keys in the console under API keys or with
POST /v1/keys.
A key id such as
key_d12af855ae0f45b9925223d65562fd0e and a display prefix such as otsk_fde66231 are not credentials. Only the full 69-character secret authenticates.Send an authenticated request
Keep the secret in an environment variable, never in source code. This call lists your most recent run and needs a key withruns_read, which the console’s Send requests set includes. It is a quick way to confirm a new key works.
200:
"runs": [], which still proves the key works.
How a key is checked
For a credential that starts withotsk_, the server runs these steps in order:
- Shape. Anything other than
otsk_followed by exactly 64 hex characters is refused with401 invalid_credentialbefore any lookup. - Lookup. The server computes the SHA-256 of the secret and looks for an active key with that digest. It never stores or compares the plaintext.
- State. A revoked key does not match, so it gets the same
401 invalid_credentialas an unknown key. It does not getkey_revoked, which only appears when you try to rotate a revoked key. - Identity. A verified key acts in the organization it was created in, with exactly the scopes it was created with. See Scopes and roles.
403 scope_denied when the credential lacks it.
Auth errors
Every auth error uses the standard JSON envelope. Branch onerror.code, and quote error.request_id when you report a problem. Responses carry no WWW-Authenticate header.
The
scope_denied message says “session” even when the credential is an API key. The code is what matters.
Retry rules
401and403: something about the credential must change. Retrying the same request returns the same error.503auth_not_configuredandtrust_keys_unavailable: retry with exponential backoff and jitter. Do not revoke or replace the key because of these.- Treat a
401as a signal to alert a person, not to loop. A key that suddenly returnsinvalid_credentialwas usually revoked or rotated by someone in your organization.
Common mistakes
Related
- API key security - how secrets are stored, shown once, revoked and rotated.
- Scopes and roles - pick the smallest set of scopes a key needs.
- invalid_credential - the full entry for the most common 401.
- Error handling - retry logic that treats 401, 403 and 503 differently.
- Request ids - what to quote when you report an auth failure.