Users & RBAC
Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.
The worker has two identities:
- Super-admin — the holder of
MASTER_TOKEN. Owns the worker. Can do anything in/admin/*. Cannot use OAuth. - User account — a row in the D1
userstable. Has a username + password. Can log into/admin/*(limited view) and is the identity behind the OAuth Custom Connector flow.
You usually create a user account for yourself even if you ARE the super-admin — so the day-to-day Claude connector has a real identity attached and the audit trail reads cleanly.
Master token vs user accounts
Section titled “Master token vs user accounts”| Master token | User account | |
|---|---|---|
| Stored where | wrangler secret MASTER_TOKEN | D1 users table, PBKDF2-hashed |
| Login surface | /admin/login → Master tab | /admin/login → User tab; OAuth /oauth/authorize |
| Scope | Everything | Whatever sites have been granted in user_sites |
Can use the MCP /mcp endpoint? | No — issue a bearer token first | Yes (via OAuth or a bearer token they mint) |
| Can mint tokens? | Yes, for any site | Yes, only for sites they’re granted |
| Can create users? | Yes | No |
| Can manage GitHub App / Cloudflare Pages settings? | Yes | No |
| Visible audit rows | Everything | Their own actions only |
| Recoverable on loss | wrangler secret put MASTER_TOKEN (regen) | Super-admin resets password |
The master token is intentionally not accepted on /mcp — you can’t paste
it as Authorization: Bearer <master> and call tools. Mint a regular bearer
token or use OAuth instead.
Creating your first user
Section titled “Creating your first user”Once the worker is deployed and you can log in with the master token:
- Sign in at
/admin/loginon the Master token tab. - Open
/admin/users. - Click + New user.
- Fill in:
- Username — kept lowercase, used at login. Cannot be changed later.
- Password — anything 12+ chars. Stored as PBKDF2 (100k rounds, SHA-256).
- Submit. The user now exists with zero site grants — they can’t do anything yet.
Granting sites
Section titled “Granting sites”A user can only see / write to sites that appear in their user_sites whitelist.
- On
/admin/users, click the user row. - Tick the sites they should access.
- Save.
The next OAuth login + every subsequent /mcp call respects the new grant
immediately (D1 is read-after-write within the same region).
Resetting a password
Section titled “Resetting a password”Forgotten password? Master-admin steps:
/admin/login→ Master tab → sign in./admin/users→ row → Reset password.- Type the new password. Tell the user out-of-band.
A user cannot reset their own password from the dashboard — the worker has no mail integration. If you self-host and want self-serve resets, that’s a worthwhile fork target.
Deleting a user
Section titled “Deleting a user”/admin/users→ row → Delete.- Confirm.
The worker:
- Removes the row from
users. - Removes their rows from
user_sites. - Revokes every bearer token where
owner_user_id = <them>(setsrevoked_at). - Revokes every OAuth access + refresh token bound to that user.
- Leaves
audit_logrows intact — theactor_user_idcolumn keeps the user_id even after deletion so history isn’t rewritten.
RBAC model in detail
Section titled “RBAC model in detail”Three tables conspire to decide “can this token call this tool on this site”:
┌──── tokens ────┐ ┌──── users ────┐ ┌── user_sites ──┐│ id │ │ id │ ┌──── │ user_id ││ token_hash │ │ username │ │ │ site_id ││ allowed_sites │ │ password_hash │ │ └────────────────┘│ allowed_tools │ └───────────────┘ ││ owner_user_id ─┼─────────────────────────────┘└────────────────┘On every MCP call:
calling_site IN token.allowed_sitesAND calling_tool IN token.allowed_toolsAND ( token.owner_user_id IS NULL -- super-admin token OR calling_site IN user_sites[token.owner_user_id])For OAuth requests:
calling_site IN user_sites[oauth_access_token.user_id]OAuth tokens don’t carry per-site scope themselves — they always grant the
full set of tools (mcp:full scope) but are gated by user_sites. That’s
why removing a site grant immediately blocks both the user’s bearer tokens AND
their OAuth session, without revoking anything.
When OAuth is bound to a user vs not
Section titled “When OAuth is bound to a user vs not”| Token kind | Bound to user? | Implication |
|---|---|---|
OAuth (oat_...) | Always | audit_log.actor_user_id records the user. |
| Bearer minted by a user | Yes (tokens.owner_user_id set) | Intersect with their user_sites. |
| Bearer minted by super-admin | No (tokens.owner_user_id IS NULL) | Bypasses user_sites; unlocks super-admin-only tools like delete_astro_route. |
That last row is why some tools refuse non-super tokens at runtime — see
delete_astro_route in the tools reference and the
E_SUPER_ADMIN_ONLY row in the errors page.
Audit trail
Section titled “Audit trail”audit_log.actor_user_id is populated from whichever identity made the call:
- OAuth call →
oauth_access_tokens.user_id - Bearer call →
tokens.owner_user_id(may be NULL = super-admin)
Regular users see only their own audit rows at /admin/audit. Super-admin
sees everything and can filter by actor_user_id to investigate one
teammate’s activity. See also Tokens & scoping for the
full token model.
Onboarding a teammate — typical flow
Section titled “Onboarding a teammate — typical flow”- You (super-admin): sign in with the master token.
- You: create user
aliceat/admin/users. Pick a strong temporary password. - You: grant
alicethe two sites she’ll work on. - You: share the temporary password with Alice through a password manager.
- Alice: signs into
/admin/login→ User tab → changes her password. - Alice: in Claude Desktop, adds the Custom Connector
pointing at the worker URL. Logs in as
aliceon the consent screen. - Done. Alice’s Claude can see her two sites and nothing else.
Common pitfalls
Section titled “Common pitfalls”- OAuth login shows “no users yet” — you haven’t created any user accounts
yet. Master tab →
/admin/users→ create one, then retry the connector. - A user can see a site they shouldn’t — check
user_sites. The dashboard hides sites without a grant; a leaked old token is the only other way in. Revoke at/admin/tokens. - Bearer token mysteriously stops working — likely the owner’s
user_siteswas trimmed. Re-grant the site or remint the token from super-admin. - I want a “read-only” user role — the schema doesn’t have role flags.
Approximate it with a bearer token whose
allowed_toolsis justlist_sites,list_drafts,get_post, etc. See Tokens & scoping.