4.6 KiB
| read_when | |||
|---|---|---|---|
|
Auth
ClickClack accepts four ways to identify a caller, in order of precedence. The
resolver lives in apps/api/internal/httpapi/server.go (currentUser).
Authorization: Bearer <token>— bearer session token.cc_sessioncookie — HTTP-only session cookie set by magic-link consume and GitHub OAuth callback.X-ClickClack-User: usr_...header — explicit user impersonation for local development and tests.- Dev fallback — the very first user in the database. Enabled by default by
clickclack serve --dev-bootstrap=trueso a fresh checkout boots into a working app without any token plumbing.
The dev fallback is the one to disable in any non-local deployment. Set
--dev-bootstrap=false and require real sessions.
Local owner bootstrap
clickclack serve calls Store.EnsureBootstrap when --dev-bootstrap is on.
That helper:
- Returns the first user if one exists.
- Otherwise creates a
Local Captainuser, aClickClackworkspace, and ageneralchannel, then returns the new user.
To pin the owner identity instead, run the CLI before serving:
clickclack admin bootstrap --name "Peter" --email steipete@gmail.com
That prints the new usr_... ID. Pass it back via X-ClickClack-User or use
the magic-link flow to mint a session.
Magic links
Magic-link tokens are short-lived bearer credentials. They can be created over HTTP or from the CLI; the consume endpoint exchanges them for a durable session.
POST /api/auth/magic/request
{ "email": "steipete@gmail.com", "display_name": "Peter" }
POST /api/auth/magic/consume
{ "token": "<token>" }
Or from the CLI, which is the V0 delivery path:
clickclack admin magic-link create --email steipete@gmail.com --name "Peter"
The client CLI can consume that token directly:
clickclack login --magic-token mgt_...
For remote agents and bots, use the resulting bearer session token. The CLI
will not send a stored bearer token to a different --server, and it skips
stored bearer tokens when --user / CLICKCLACK_USER_ID is set without an
explicit --token.
ConsumeMagicLink returns {user, session, token} and sets cc_session as an
HTTP-only cookie. Browsers can drop the body; bots should hold the
session.token for the Authorization header.
GitHub OAuth (optional)
GitHub OAuth is opt-in. Set all three env vars (or the equivalent config keys) before serving:
CLICKCLACK_PUBLIC_URL=https://chat.example.com
CLICKCLACK_GITHUB_CLIENT_ID=...
CLICKCLACK_GITHUB_CLIENT_SECRET=...
CLICKCLACK_GITHUB_ALLOWED_ORG=openclaw
Without those, GET /api/auth/github/start returns 501.
Flow:
GET /api/auth/github/startsets a state cookie and redirects to GitHub.- GitHub redirects back to
GET /api/auth/github/callback?code&state. - The handler exchanges the code, fetches
/userand primary/user/emails, checks org membership whenCLICKCLACK_GITHUB_ALLOWED_ORGis set, upserts a user keyed by(provider="github", provider_subject=<github id>), creates a session, setscc_session, redirects to/.
The redirect URL is derived from CLICKCLACK_PUBLIC_URL when set, otherwise
from the request scheme/host. Configure GitHub with <public-url>/api/auth/github/callback.
Org-gated deployments request read:org. GitHub only returns private org
membership after the user grants that scope, so OpenClaw-only hosting should set
CLICKCLACK_GITHUB_ALLOWED_ORG=openclaw and CLICKCLACK_DEV_BOOTSTRAP=false.
When the org check passes, the user is automatically joined to the first
workspace; if no workspace exists yet, ClickClack creates a default workspace
with a general channel.
Authorization
Every store mutation that touches a workspace runs requireMembership (or the
in-tx variant). API handlers do not duplicate that check — trust the store
layer for it. WebSocket subscriptions revalidate GetWorkspace before
upgrading.
Roles today are limited to owner and member, used only by the bootstrap
helper. There is no role enforcement on writes yet beyond membership.
Sessions
sessions are bearer tokens with an expires_at. GetSessionUser resolves the
token to a User. There is no refresh flow — issue a new session when one
expires.
What is intentionally missing
- Email/password login.
- Password reset.
- SMTP delivery for magic links (V0 prints the token; V1 will add delivery).
- Per-channel ACLs, role-based permissions, audit logs.