Bỏ qua để đến nội dung

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 users table. 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 tokenUser account
Stored wherewrangler secret MASTER_TOKEND1 users table, PBKDF2-hashed
Login surface/admin/login → Master tab/admin/login → User tab; OAuth /oauth/authorize
ScopeEverythingWhatever sites have been granted in user_sites
Can use the MCP /mcp endpoint?No — issue a bearer token firstYes (via OAuth or a bearer token they mint)
Can mint tokens?Yes, for any siteYes, only for sites they’re granted
Can create users?YesNo
Can manage GitHub App / Cloudflare Pages settings?YesNo
Visible audit rowsEverythingTheir own actions only
Recoverable on losswrangler 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.

Once the worker is deployed and you can log in with the master token:

  1. Sign in at /admin/login on the Master token tab.
  2. Open /admin/users.
  3. Click + New user.
  4. Fill in:
    • Username — kept lowercase, used at login. Cannot be changed later.
    • Password — anything 12+ chars. Stored as PBKDF2 (100k rounds, SHA-256).
  5. Submit. The user now exists with zero site grants — they can’t do anything yet.

A user can only see / write to sites that appear in their user_sites whitelist.

  1. On /admin/users, click the user row.
  2. Tick the sites they should access.
  3. Save.

The next OAuth login + every subsequent /mcp call respects the new grant immediately (D1 is read-after-write within the same region).

Forgotten password? Master-admin steps:

  1. /admin/login → Master tab → sign in.
  2. /admin/users → row → Reset password.
  3. 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.

  1. /admin/users → row → Delete.
  2. Confirm.

The worker:

  • Removes the row from users.
  • Removes their rows from user_sites.
  • Revokes every bearer token where owner_user_id = <them> (sets revoked_at).
  • Revokes every OAuth access + refresh token bound to that user.
  • Leaves audit_log rows intact — the actor_user_id column keeps the user_id even after deletion so history isn’t rewritten.

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_sites
AND calling_tool IN token.allowed_tools
AND (
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.

Token kindBound to user?Implication
OAuth (oat_...)Alwaysaudit_log.actor_user_id records the user.
Bearer minted by a userYes (tokens.owner_user_id set)Intersect with their user_sites.
Bearer minted by super-adminNo (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_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.

  1. You (super-admin): sign in with the master token.
  2. You: create user alice at /admin/users. Pick a strong temporary password.
  3. You: grant alice the two sites she’ll work on.
  4. You: share the temporary password with Alice through a password manager.
  5. Alice: signs into /admin/login → User tab → changes her password.
  6. Alice: in Claude Desktop, adds the Custom Connector pointing at the worker URL. Logs in as alice on the consent screen.
  7. Done. Alice’s Claude can see her two sites and nothing else.
  • 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_sites was 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_tools is just list_sites, list_drafts, get_post, etc. See Tokens & scoping.