OAuth Scopes
The supported OAuth/OIDC scopes and what each one grants your app permission to do on the user's workspace.
OAuth Scopes
Scopes are the permissions your app asks for at the consent screen. Request the minimum: users are more likely to authorize, and the consent screen renders cleaner when you don't ask for everything.
The user can grant a subset of the scopes you request (by unchecking individual ones on the consent screen). Your app must handle that gracefully — check what's actually in the access token's scope claim, not what you originally requested.
Identity scopes
| Scope | What it adds |
|---|---|
openid | Required for sign-in. Enables the id_token in the token-endpoint response and gives you the user's stable sub identifier. |
email | Adds email and email_verified claims to the ID token and to the /userinfo response. |
profile | Adds name to the ID token and /userinfo. |
offline_access | Issues a refresh_token alongside the access token, so your app can mint new access tokens without re-prompting the user. |
These four scopes give your app identity only — they don't unlock any workspace data.
Workspace scopes
Workspace scopes give your app the ability to act on the single workspace the user selects at consent time. The access token carries a workspace_id claim and your app's calls are restricted to that workspace.
| Scope | Grants |
|---|---|
workspace:read | Read operational data in the selected workspace: workflows, components, executions, members, environment-variable names (not values), workspace API key labels, MCP settings. Does NOT include financial data — request workspace:read.billing for that. |
workspace:read.billing | Read financial data: credit balance (paid + usage + total), billing transactions, payments, billing information, subscription status. Independent of workspace:read so apps that only need workflow data do not also see your billing history. |
workspace:write | Read everything in workspace:read, plus create / edit / delete workflows, trigger executions, cancel and retry runs, manage environment variables. |
workspace:api_keys | Narrow grant for creating named workspace API keys (the same key + secret you would receive from the workspace settings UI). Independent from workspace:write — apps that only need to mint API keys don't have to ask for full admin. |
workspace:admin | Implies all four scopes above. Adds: invite + remove members, revoke API keys, change workspace settings, manage billing (top up, change plan, cancel subscription). |
Tier hierarchy
workspace:admin ⊃ workspace:write ⊃ workspace:read
⊃ workspace:read.billing
⊃ workspace:api_keys
workspace:read.billing and workspace:api_keys are sibling slices to the write tier — they sit beside workspace:write rather than under it. An app holding workspace:write can create workflows but cannot mint API keys or read billing; an app holding workspace:read.billing can see the credit balance but cannot list workflows. Request each slice independently.
Picking the right scopes
Some common integration shapes and the scopes they need:
| Integration | Scopes to request |
|---|---|
| "Sign in to my app with Zafeguard" — identity only, no workspace data | openid email profile |
| Identity + stay-signed-in | openid email profile offline_access |
| Read-only dashboard that mirrors workflow runs | openid offline_access workspace:read |
| Accounting tool reading credit balance + billing transactions | openid offline_access workspace:read.billing |
| Workflow builder / automation client | openid offline_access workspace:write |
| Provisioning agent that needs to mint a workspace API key on first run | openid offline_access workspace:api_keys |
| Full admin surface (rare; only for ops tooling) | openid offline_access workspace:admin |
Consent-screen privilege rule
A user can only grant a workspace scope they themselves hold on that workspace. Examples:
- A regular workspace member (no admin permissions) tries to consent to
workspace:admin→ the consent endpoint rejects the request, and the consent UI greys out workspaces they can't grant the requested scope on. - A user who is a member of two workspaces — admin on one, read-only on the other — can grant
workspace:adminfor the first workspace but onlyworkspace:readfor the second.
This means a third-party app cannot escalate privileges by asking for a wider scope than the consenting user holds.
In addition, every consent requires the workspace-level permission authorize_workspace_connected_apps regardless of which scopes are being granted. Workspace owners hold this implicitly; members need it granted explicitly to be able to authorize any third-party app on the workspace.
Access token claim shape
Once your app receives an access token, the claims it carries:
{
"iss": "https://api.zafeguard.com",
"sub": "9c3f4b2a-7e8d-4d1a-a3b0-f6e2a4b8c1d9",
"aud": "zfg_abc123…",
"client_id": "zfg_abc123…",
"workspace_id": "f1e2d3c4-b5a6-7890-1234-567890abcdef",
"scope": "openid email profile workspace:read",
"iat": 1748145600,
"exp": 1748149200
}subis stable per (user, app) — the same user signing in to the same app always sees the samesub. Use it as your local user identifier.workspace_idis the workspace the user selected for this authorization. Pass it to any workspace-scoped Zafeguard endpoint you call; mismatched values are rejected with 403.scopeis the actual granted set (could be narrower than what you requested if the user unchecked items).
ID token claim shape
The ID token carries identity-only claims:
{
"iss": "https://api.zafeguard.com",
"sub": "9c3f4b2a-7e8d-4d1a-a3b0-f6e2a4b8c1d9",
"aud": "zfg_abc123…",
"nonce": "<the nonce you sent on /authorize>",
"auth_time": 1748145600,
"email": "alice@example.com",
"email_verified": true,
"name": "Alice Example",
"iat": 1748145600,
"exp": 1748149200
}Fields are present only when the matching scope is granted (email / email_verified need email; name needs profile).