Data Hub

Security & permissions

Roles and what each can do, personal-access-token scopes, how authentication works, and good token hygiene.

ForAdministrators and members

This page explains who can do what in Data Hub: the two roles, the scope system that gates token-authenticated requests, and how to handle tokens safely. For the mechanics of creating and revoking tokens, see Managing tokens.

Authentication

The API accepts two kinds of credentials:

  • Session cookies: used by the web dashboard (Google OAuth via NextAuth). Session callers implicitly hold every scope; scope checks only apply to token requests.
  • Bearer tokens: personal access tokens (dhub_…) used by the watcher, the Lambda, and MCP clients, sent as Authorization: Bearer <token>.

Tokens are hashed with SHA-256 before storage; the plaintext is shown exactly once, at creation.

Roles

RoleCan do
MemberSign in to the dashboard; view instruments, runs, files, and the token audit list. Cannot mint or delete tokens, confirm/update instruments, or manage other users.
AdminEverything members can, plus: confirm and update instruments, create and revoke any user's tokens, and promote/demote other users.

The first admin is bootstrapped from the ADMIN_EMAILS environment variable (comma-separated, case-insensitive); listed users are promoted on every sign-in. After that, any admin can promote others from Settings → Members. Admins cannot demote themselves: that guards against locking the workspace out of its last admin.

Admin-gated operations

A subset of mutations require the admin role in addition to (or instead of) a scope check:

  • PATCH /api/v1/instruments/:id: session callers must be admin (bearer-token automation still uses instruments:write, so watcher/Lambda flows are unaffected).
  • POST /api/v1/tokens and DELETE /api/v1/tokens/:id: admin-only, session-only. Bearer tokens cannot manage other tokens.
  • GET /api/v1/users, PATCH /api/v1/users/:userId: admin-only, session-only. Used by Settings → Members.

Token scopes

Every personal access token carries an array of permission scopes. A token-authenticated request is rejected with 403 FORBIDDEN when the token's scopes don't include the scope a route requires. Issue tokens with the least privilege they need.

ScopeGrants
instruments:readList/read instruments
instruments:writeCreate/update instruments
runs:readList/read runs and their comments
runs:writeCreate/update/delete runs, comments, attributions, and run-level upload/reprocess endpoints
files:readRead file metadata, download files, download run archives
files:writeCreate/update/delete file records and reprocess files
watchers:readRead watcher state (list, heartbeats, events, config, upload queue, update-check)
watchers:writeRegister/deregister watchers, post heartbeats and events, push config
archive-jobs:readRead archive job state (reserved for future endpoints)
archive-jobs:writeUpdate archive jobs (Lambda callback)
*Wildcard: matches every scope. Reserved for legacy backfilled tokens; POST /api/v1/tokens rejects * from API callers.

MCP tools enforce the same scopes as their REST counterparts: a token with runs:read over REST also covers the read-side run tools over MCP. There's no MCP-specific scope vocabulary.

A typical watcher token needs instruments:read, instruments:write, runs:write, files:write, and watchers:write. A read-only MCP/analysis token needs the :read scopes for the data you want to query.

Token hygiene

  • Name tokens descriptively (e.g. “FPLC watcher – Lab 201”) so you can tell what each one is for.
  • Set expirations for temporary setups.
  • Scope to least privilege: don't hand out broad tokens for a single read-only integration.
  • Revoke immediately when a watcher is decommissioned or a token may have been exposed. Revocation is instant; clients using the token start getting 401 Unauthorized. See After revoking a token.

Public pages, gated bodies

Some web pages (dashboard, instruments, run detail, settings) are reachable without a session so link unfurlers can read page metadata. The page body renders a sign-in prompt instead of real data when there's no session, and three independent layers (robots metadata, robots.txt, and an X-Robots-Tag header) keep the product app out of search indexes. The /api/v1/* surface always requires a session cookie or bearer token.

On this page