Start
Authentication
Session cookie, Bearer token, the two role axes and the rate limit.
Every installation requires an account, and no environment or screen switch turns that off. The only exception is demo mode, where anyone comes in without a credential.
Two credentials, one identity
Both end at the same identity, and the cookie takes precedence: in a signed-in tab that also sent the header, the session identity wins.
TOKEN=... # copied from My account → Security
curl -s http://localhost:3000/api/board \
-H "Authorization: Bearer $TOKEN"There is no server secret to configure
The session token is opaque (32 random bytes), and what is stored is its sha256; the password is derived with scrypt. No key to generate, rotate or leak: a database dump returns no usable credential.
The API token
- There is one per person: generating again revokes the previous one, so revoking is a single action.
- The plain value comes out once, in the response that created it. Lost it, make another.
- What stays on the row, besides the
sha256, are the last four characters, enough for the screen to say which token your script carries.
Two role axes, and the narrowest wins
A VIEWER of the installation writes nowhere, even as a MEMBER of a workspace. And ADMIN is an implicit member of all of them: without that rule, a workspace whose last member left would have nobody able to give access back.
The matrix, and the rule that closes it
/api/profile* has its own entry because the default rule would send writing to MEMBER, and that would lock a VIEWER out of their own profile: they do not write on the board, but they do change their own password and avatar.
The second check: which workspace
The role check does not know which workspace the resource belongs to: /api/cards/[id] carries only the card id. So workspace access is checked inside the transaction, alongside reading the resource.
Not being a member is 403, not 404
Asking for a resource in a workspace the account does not reach returns 403, not 404. The answer is then the same for an id that exists and for a made-up one, and it reveals no workspace.
Abuse control
The login counter includes the target e-mail: in an office behind one IP, one person's typo does not lock the others out. The 429 always carries Retry-After, in seconds.