Skip to main content
Every protected endpoint is gated by a scope. API keys carry the scopes you select at creation. Dashboard users authenticate with session cookies; their organization role is mapped to the same scopes so the same middleware can gate both call paths.

The scopes

These are the only scopes today. The middleware rejects any request whose key doesn’t carry the required scope with FORBIDDEN.

Pick the smallest set

A key that only creates sessions needs sessions:write — it does not need sessions:read to create. A backend that processes webhooks needs nothing if it only verifies and stores deliveries; webhook events arrive at your endpoint without any scope check on your side. A reporting tool that lists past sessions needs only sessions:read. Don’t grant webhooks:write to a process that only verifies signatures. Treat scopes the way you’d treat IAM permissions.

Dashboard session mapping

Session-cookie callers (the dashboard) inherit scopes from the user’s role on the active organization: Reads need any role. Writes need at least admin. This mirrors what the dashboard UI exposes: member-role users see resources but can’t change them.

Where the mapping lives

In the codebase, the canonical mapping is packages/auth/src/permissions.ts. The middleware that enforces it on every /v1/* request is in apps/api/src/v1/auth.ts. If you’re self-hosting and need to change either, those are the two files to read together.