Version

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>, live on production or test on every other environment. A test token is refused on production with AUTHENTICATION_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/tokens by a token that holds token:create. A minted token is attenuated: its abilities must be a subset of the caller's, and token:create itself 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:

  1. The API validates the bearer token and attaches it to the request.
  2. 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).
  3. Any scope:project:<uuid> entries restrict the token further; a request touching a project outside the allow-list returns TENANT_MISMATCH (HTTP 404) so existence is never leaked.
  4. 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:

  1. Mint a replacement with identical abilities.
  2. Swap the secret in your integration (environment variable, secret manager, pipeline variable).
  3. 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.

How is this guide?

Last updated on

Version

On this page

What changed recentlyEvery release of Zuse Bifrost, with the pages it touched.

For AI agents: llms.txt · llms-full.txt