B2B tenant access
The B2B portal authenticates a human with GitHub OAuth or a single-use email magic link. It does not use a shared dashboard API key. Both methods resolve to the same stable dashboard_users.id, and the gateway checks that identity against the D1 dashboard_memberships table on every request. This leaves room for passkeys/WebAuthn without changing tenant authorization.
Each request must select a tenant the user belongs to. A single membership is selected automatically; users with multiple memberships select one with the tenant query parameter. The gateway verifies the membership on every request, so a client ID supplied by the browser is never trusted by itself.
| Role | Read sessions, metrics, audit | Replay webhooks | Manage webhook | Manage API keys | Manage members/billing |
|---|---|---|---|---|---|
owner | Yes | Yes | Yes | Yes | Yes |
admin | Yes | Yes | Yes | Yes | No |
developer | Yes | Yes | Yes | No | No |
viewer | Yes | No | No | No | No |
Grant access from apps/gateway:
pnpm grant:dashboard-membership -- \
--github-user-id 123456 \
--github-login daliborgogic \
--client-id acme-bank \
--role owner \
--env staging --remoteOr provision an email login with --email owner@example.com. The numeric GitHub ID is intentional when GitHub is used: login names can change, while the numeric identity remains stable. API keys remain separate machine-to-machine credentials for customer integrations.
Owners can manage email and GitHub members from Settings. The Gateway resolves GitHub usernames to immutable IDs before storing a membership. A later rename changes only the display login; authorization continues to use the original ID. If another account claims a released username, GitHub returns a different ID, so that account has no membership.
The API protects the last Owner from removal or downgrade. It also requires the active tenant to be selected server-side for every member, API-key, and webhook action. The dashboard currently exposes Staging only. Production requests fail closed until a production Worker and service binding are provisioned.
Audit log
GET /dashboard/api/audit-log accepts tenant, range (24h, 7d or 30d) and limit (capped at 100). It returns only tenant-scoped operational metadata: session ID, status, credential/issuer identifiers, latency, error code, prevHash, entryHash and chainIntact. The Gateway validates both the entry's SHA-256 self-consistency and the existence of its predecessor link without exposing records from other tenants.