Browse docs
Docs /configure/api-tokens
Configure

API tokens

Every non-browser client — the CLI, the GitHub Action, the MCP server — authenticates with a bearer token.

The izri_ prefix is load-bearing

All tokens start with izri_. This is not cosmetic. The API short-circuits to bearer-token validation only when it sees that prefix; anything else falls through to cookie-session handling and produces an opaque 401 with no explanation.

If you get an unexplained 401 with a token you believe is valid, check the prefix before anything else. A truncated copy-paste that lost the prefix looks exactly like an expired token.

Minting a token

From organization settings, create a token and select its scopes. Copy it immediately — it is shown once and stored hashed.

A token can hold a subset of your role's scopes, never more. See organizations and roles for the full role-to-scope matrix.

Scoping

Grant the minimum the client needs.

Client Typical scopes
GitHub Action analysis:run, tests:run, tests:read, projects:read
CLI (local dev) analysis:run, tests:run, tests:read, projects:read
MCP server projects:read, tests:read, analysis:read — add analysis:run to let the agent run scope checks and tests:run to let it trigger runs
Read-only dashboards projects:read, tests:read, analysis:read

A CI token does not need tokens:write or org:write. If a leaked CI token can mint more tokens, the blast radius of a leak is unbounded. Nor does it need analysis:approve: keep baseline approval with people, so a leaked CI token cannot wave its own visual changes through.

What each write needs

Every change a token makes to a project needs the matching scope. A token without it gets 403 with the scope named, whoever minted it.

Write Scope
Trigger a test run, upload CI evidence (izri run, izri upload, /api/ci/*) tests:run
Scope check, derive a scope config, re-analyze a PR, analyze a repository analysis:run
Approve or revoke a visual baseline analysis:approve
Project settings, quality policy, scope config, cost-tracking reset projects:write
Delete a project projects:delete
Inbound webhook configuration; outbound webhook subscriptions (create, update, rotate secret, delete, test) — the latter also need an OWNER or ADMIN creator webhooks:write

A token needs at least one scope; the API refuses an empty list.

Using a token

export IZRI_API_TOKEN=izri_xxxxxxxxxxxx
export IZRI_API_URL=https://api.izri.ai
- uses: legendify-dev/izri/apps/github-action@v1
  with:
    api-token: ${{ secrets.IZRI_API_TOKEN }}

Directly against the API:

curl -H "Authorization: Bearer izri_xxxxxxxxxxxx" \
     https://api.izri.ai/health

Rotation

  1. Mint the new token.
  2. Update every consumer — CI secrets, local environments, MCP configs.
  3. Revoke the old one.

In that order. Revoking first means a window where CI fails on every PR.

Tokens do not expire on their own. Rotate on a schedule you choose, and immediately whenever someone with token-minting rights leaves.

Tokens follow their creator's role

A token's scopes are fixed when it's created, but its write access also depends on its creator's current role. Demote the creator to VIEWER, or remove them from the organization, and every token they minted stops writing (reads keep working). Promoting someone does not widen tokens they already minted — reissue them.

Changing a member's role or removing them from the organization also revokes every token they minted there, so after a role change the person mints fresh tokens with the scopes their new role allows. The creator-role check above is the backstop for anything that bypasses that.

A token can only hand out what it holds: minting or rotating with a token refuses any scope the calling token itself lacks, so tokens:write on its own never becomes analysis:approve or projects:write.

Never commit a token

Use repository secrets in CI and your environment locally. A token in git history is compromised even after the commit is removed — rotate it rather than rewriting history.

Reading this with an agent? /docs/configure/api-tokens.md serves the raw markdown.

Edit this page on GitHub →All docs