Authentication

Every CloudPeek API call (except a few public endpoints) must be authenticated with a bearer token. This page explains how to get a token, how to send it, how tenant scoping works, and the permission model behind every endpoint.

The scheme: bearer tokens

CloudPeek uses OpenID Connect (OIDC) access tokens issued by Zitadel, the identity provider. Send the token on every request:

Authorization: Bearer <token>

A missing or malformed header returns 401 "Missing or invalid Authorization header".

Two kinds of token work:

  • OIDC access token (JWT): short-lived, obtained via the standard OAuth login flow.
  • Personal Access Token (PAT): a longer-lived token from Zitadel, convenient for scripts and automation. PATs are validated by introspection, so they work even though they aren't JWTs.
Tip

For server-to-server scripts, a PAT is usually easiest: create one in your identity provider, store it as a secret, and send it as the bearer token.

Getting a token via the login flow

The web app and CLI run the OAuth Authorization-Code + PKCE flow against Zitadel. The API helps you discover the right endpoints. These auth endpoints are public (no token needed):

MethodPathPurpose
GET/api/v1/auth/configOIDC discovery: issuer, client/project IDs, scopes, and the authorize/token/userinfo/jwks endpoints
GET/api/v1/auth/login?redirect_uri=…Redirects to the identity provider's login
POST/api/v1/auth/loginEmail/password login via the identity provider; body { email, password, code_challenge, redirect_uri }{ callback_url }
POST/api/v1/auth/refreshExchange a refresh token; body { refresh_token }{ access_token, refresh_token, token_type }
POST/api/v1/auth/forgot-passwordBody { email }204
POST/api/v1/auth/reset-passwordBody { email, code, new_password }204
GET/api/v1/auth/capabilitiesWhether self-service password reset is enabled

Confirming who you are

Once you have a token, confirm your identity and see your roles:

curl -s "http://localhost:8000/api/v1/auth/me" \
  -H "Authorization: Bearer $CLOUDPEEK_TOKEN"

GET /api/v1/auth/me returns your profile, including id, email, name, org_id, roles, roles_by_org, and org_ids. Other authenticated auth endpoints:

MethodPathPurpose
PATCH/api/v1/auth/meUpdate your profile (given_name, family_name, display_name, phone)
POST/api/v1/auth/me/passwordChange your password (current_password, new_password)
GET/api/v1/auth/tenantsList tenants you can access
GET/api/v1/auth/preferred-tenantYour default tenant
PUT/api/v1/auth/preferred-tenantSet your default tenant ({ org_id })
POST/api/v1/auth/logoutRevoke tokens

Tenant scoping with X-Tenant-Id

CloudPeek is multi-tenant. By default your requests are scoped to your primary tenant (organisation). To target a specific tenant, or several, add the X-Tenant-Id header:

X-Tenant-Id valueEffect
(omitted)Your default/primary tenant
org-123Scope to that one tenant
org-1,org-2Multi-tenant query across those tenants
*All tenants you can access

Requesting a tenant you don't have access to returns 403. Example:

curl -s "http://localhost:8000/api/v1/incidents/" \
  -H "Authorization: Bearer $CLOUDPEEK_TOKEN" \
  -H "X-Tenant-Id: org-123"
Note

In single-tenant deployments, the deployment is pinned to one tenant and requests for any other tenant are rejected. You generally don't need X-Tenant-Id there.

Permissions (RBAC)

Authorisation is role-based. A role is a set of permissions, and each permission is a resource:action string, for example incident:read, tools:create, wiki:write. Wildcards are supported: *:* (full admin), incident:* (all incident actions), *:read.

Each endpoint requires a specific permission. If your token's roles don't include it, you get:

{ "error": "Permission denied: requires incident:read" }

with status 403. Throughout the API reference, the permission an endpoint needs is noted next to it. Roles are assigned per tenant, you can be an admin in one tenant and read-only in another. Administrators manage roles in User Management, where presets (Global Admin, Tenant Admin, Senior Analyst, Analyst, Read-only) bundle common permissions.

Putting it together

# 1. Discover OIDC config (public)
curl -s http://localhost:8000/api/v1/auth/config

# 2. With a token, confirm identity and roles
curl -s http://localhost:8000/api/v1/auth/me \
  -H "Authorization: Bearer $CLOUDPEEK_TOKEN"

# 3. Make a scoped, authorised call
curl -s "http://localhost:8000/api/v1/incidents/?limit=10" \
  -H "Authorization: Bearer $CLOUDPEEK_TOKEN" \
  -H "X-Tenant-Id: org-123"

Next

© 2026 CloudPeek. Agentic AI for high-consequence security operations.