Authentication
Personal access tokens, ability scopes and tenant resolution for the REST API and the MCP server, and what the API will not accept.
Zuse Bifrost authenticates every REST API request through a personal access token. Session cookies, OAuth and SAML are not accepted on the API host; tokens only. The MCP server accepts the same tokens and, in addition, the OAuth 2.1 access tokens it issues when a client signs you in; see MCP authentication.
Token format
Tokens are opaque strings of the form:
zg_<env>_<id>_<secret>Three fixed segments, underscore-separated:
zg_, the Zuse Bifrost prefix, so a leaked token is recognisable in a repository scan.<env>,liveon production orteston every other environment. Atesttoken is refused on production withAUTHENTICATION_REQUIRED, so a leak across environments never grants access.<id>, the integer primary key of the stored row, which lets the server look the token up without scanning every row's hash.<secret>, 64 hex characters of randomness. Only this segment is secret; the other three are metadata.
Other properties:
- A token is revealed exactly once, at the moment of creation. The server stores only a hash of the secret.
- A token does not expire by default; revoke unused tokens from the settings page.
- Tokens are minted from Account Settings → API Tokens, or over the API with
POST /v1/tokensby a token that holdstoken:create. A minted token is attenuated: its abilities must be a subset of the caller's, andtoken:createitself is never inherited, so a leaked automation token cannot spin up a stronger one.
Ability-scoped authorization
Every token carries an explicit list of ability strings (see the ability catalogue). Each REST endpoint and each MCP tool checks for a specific ability before executing; a token missing the ability receives TOKEN_MISSING_ABILITY, naming the ability in error.context.required_ability.
Example minimal grant for a pipeline that reports deployments and reads the project it deploys:
team:view
project:view
deployment:record
scope:team:<team-uuid>
scope:project:<project-uuid>The scope:team:<uuid> entry is frozen at token-mint time. Switching teams in the app never widens an existing token; issuing the token asserts intent.
Tenant resolution
When a request arrives on the API host:
- The API validates the bearer token and attaches it to the request.
- The server reads
scope:team:<uuid>from the token's ability list and scopes every query to that team for the duration of the request (no database write). - Any
scope:project:<uuid>entries restrict the token further; a request touching a project outside the allow-list returnsTENANT_MISMATCH(HTTP 404) so existence is never leaked. - A guest's token is confined to the projects they were invited to, whatever abilities it carries: the token can never outrank the person.
A token minted without a scope:team:<uuid> entry fails every request with
TENANT_MISMATCH. The settings page appends the scope automatically; only
hand-crafted tokens miss it.
Test the token
The canonical probe is GET /v1/teams/current:
curl "https://api.example.test/v1/teams/current" \
-H "Authorization: Bearer zg_live_..."A 200 response with data.id matching the team you minted against confirms the token is valid, the bearer header was accepted, the team context was resolved, and the token carries team:view. GET /v1/me answers who the token belongs to, every team they hold and where their alerts go.
For an unauthenticated health check:
curl "https://api.example.test/v1/ping"Revocation
Revoke tokens from Account Settings → API Tokens, or with DELETE /v1/tokens/{token} from another token holding token:delete (a token cannot revoke itself). Revocations take effect on the next call across every surface. Clients still holding the token receive 401 AUTHENTICATION_REQUIRED on their next request, and the owner is told by a Security alert when a token is minted.
Rotation
To rotate a token:
- Mint a replacement with identical abilities.
- Swap the secret in your integration (environment variable, secret manager, pipeline variable).
- Revoke the old token.
Webhook endpoint signing secrets follow a separate rotation flow: POST /v1/webhook-endpoints/{endpoint}/rotate-secret.
Security expectations
- Never commit a token to a repository. The
zg_prefix makes a leak easy to spot. - Store tokens in a secret manager or the hosting platform's variables. Do not hard-code them in client-side JavaScript.
- Grant the minimum ability set required. The ability catalogue lets you tailor grants precisely.
Related
- Ability catalogue: every accepted ability string.
- Tenancy and scopes: how
scope:teamandscope:projectcombine. - Errors: every auth-related error code with remediation.
How is this guide?
Last updated on
REST API Quickstart
Mint a personal access token, call your first endpoint and receive your first signed webhook, end to end in under five minutes.
Ability Catalogue
Every ability string a token can carry, how the catalogue mirrors the team permissions, what enforces it on the API today, and how to pick the right ones when minting.