Accounts and access
Who can get into the instance, and what they can do once in, is controlled at three levels: whether someone can make an account at all, what role their account holds inside a workspace, and what a token or agent acting on their behalf is allowed to touch.
Getting an account
Accounts are created by signing up. Whether signup is open is a single setting,
PUBLIC_SIGNUP_ENABLED, and in a production build it is closed by default.
That's the safe default for anything reachable beyond your own hands: nobody
makes an account unless you let them.
The intended flow after first setup is invites, not open signup. As the operator
you mint a sign-up invite from the admin console; the person follows the link and
registers into the workspace you pointed them at. To open the door wide (a
household instance where signup being on is harmless), set
PUBLIC_SIGNUP_ENABLED=true and bring the stack up.
Roles inside a workspace
Every membership in a workspace carries a role, from most to least authority: owner, admin, editor, member, guest. Owners and admins run the workspace; editors work in it; members and guests start with almost nothing and see only what you grant.
Below those broad roles, permissions are individual capabilities (adjust stock, create a part, run a specific action). You grant them to a person one at a time, or bundle them into a custom role you define and assign. What someone lacks the capability for is both hidden in the interface and refused by the server, and the two decisions come from the same source, so the UI never shows something the server would block. The full treatment is in People and permissions.
Above every workspace sits the operator tier: the person hosting the instance,
named by email in SUPERADMIN_EMAILS, who gets the cross-workspace admin console.
That's a separate layer from the per-workspace roles, described in
Self-hosting.
Sessions
Logging in creates a signed session that lasts SESSION_TTL_DAYS, 30 days by
default and configurable in .env. Sessions are signed with JWT_SECRET; rotate
that secret and every session is invalidated at once, which is the blunt way to
sign everyone out if you suspect a token leaked. Individual sessions can be
revoked without touching the secret.
API tokens for scripts and agents
People log in; scripts and agents use API tokens. A token is minted from your account settings, tied to your user, and shown once at creation (only a hash is stored, so it can't be recovered later, only replaced). Tokens can carry an expiry, and you can revoke one at any time.
Two properties matter for keeping a token narrow:
- Scopes are deny-by-default. A token minted with a scope can reach only the endpoints that scope allows, and nothing else, even though it carries your identity. A token scoped to one job (say, feeding an edge bridge, or driving your open browser tab) cannot read workspace data or mint more tokens. A token minted with no scope is unrestricted, so scope the ones you hand to automation.
- Driving is its own grant. The token scope that lets an assistant operate
your open Cobblr tab (
drive:control) navigates the interface and reads or writes no data on its own; it's also gated by a per-workspace toggle that is off by default. Connecting an assistant this way is covered in Connecting Claude.
Recovering access
Because you own the box, being locked out is always fixable with an .env edit
and a restart. If signup is closed and there's no account at all, set
PUBLIC_SIGNUP_ENABLED=true, run docker compose up -d, register, then close it
again. If you have an account but no admin console, add that account's email to
SUPERADMIN_EMAILS and bring the stack up; the operator check reads the list
live, so the existing account is granted the tier retroactively. The step-by-step
version is in Operating.