Full detail in Credentials.
Staff sessions
Get one from sign-up, sign-in, or the two-factor exchange:two_factor_required, then exchange the challenge at
/v1/auth/two-factor within 5 minutes. See
Two-factor.
Then send it on every request:
API keys
Server-side only. Created in the panel, shown once./v1/me once at start-up to confirm which one you are holding.
Publishable keys
Not a header. It goes in the body of the endpoints that accept it:Origin
header is refused.
Contact sessions
Minted by boot, a redeemed magic link, hosted sign-in, or email verification. Reads that contact and nothing else.verified on the session says whether the identity behind it was proven. An
unverified session is usable and marked, but barred from anything another person’s
data could leak through.
Failures
Missing, malformed, expired or revoked credential — and also “you are not a
member of that organization”, because the membership JOIN matches nothing and
distinguishing the two would leak that the organization exists.
Authenticated, but your role does not carry the permission. Different from
401:
signing in again will not help.Also the answer for a resource in another organization or another environment.
The 404 never reveals which.
Bringing the wrong family
A well-formed credential from another family is told so, rather than getting a flat “invalid”:401
Not revealing whether an account exists
Several endpoints answer identically whether or not an address is known. This is deliberate and worth preserving if you touch these paths:
Without the timing equalization only real accounts would pay bcrypt’s tens of
milliseconds, and latency alone would answer the question the status code refuses
to.