Authentication
LocalMind has two authentication tracks that resolve to the same AuthContext,
so endpoints never need to know whether the caller is a human or a machine.
Session (human)
The dashboard authenticates with the better-auth.session_token cookie, set at
login and sent automatically by the browser (credentials: include). There is
no Authorization header for session auth.
Sign-in is passwordless:
| Method | Description |
|---|---|
| Email code | A one-time code sent to your email |
| Passkey | Passwordless WebAuthn, phishing-resistant and a strong second factor |
| Google / GitHub | Social sign-in |
Optional TOTP two-factor adds an authenticator-app challenge. Sensitive actions — deleting a project, transferring ownership, minting an API key, rotating a webhook secret — require a fresh step-up re-verification.
API key (machine)
Server-to-server access uses a project-scoped key passed as a Bearer token:
curl -H "Authorization: Bearer $LOCALMIND_API_KEY" \
https://api.localmind.app/api/v1/projects/{projectId}/membersThree hard rules define an API key:
- Locked to one project — a key created in Project A returns 403 for Project B.
- Never carries system permissions — platform operations require a real human session.
- Cannot escalate — a key's permission scope is a subset of its creator's project role at creation time and never grows.
The full key is shown once at creation; only a short hint is stored afterward. Scopes are enforced fail-closed — a key with an empty scope set is denied on any protected endpoint. Revoke a key from the dashboard and it stops working immediately via introspection.
Permissions
Authorization always checks a permission string, never a role name. See Permissions & roles for the two-axis model and the full project-role matrix.