Service accounts

Machine identities for CI pipelines and agents, managed from the console or the CLI.

Service accounts

A service account is a machine identity, separate from a human member, for CI pipelines and agents that need to authenticate headlessly. It binds one of the organization's roles (Owner, Admin, Editor or Viewer) the same way a human member does, and authenticates with an OAuth2 client_id / client_secret pair rather than an interactive login.

Not a Zitadel personal access token

An older revision of docs/v2/modules/02-multi-tenancy/api.md describes service accounts as issuing a Zitadel PAT. The console (settings/service-accounts.tsx) and the backend it calls issue an OAuth2 client_credentials secret instead, consumed by up0 auth login --client-id --client-secret. That doc page is stale; this page reflects the code.

Creating the first one

The first service account for an organization is created from the console, Settings → Service accounts, gated to the Owner role. There is no headless bootstrap: something has to exist before anything can authenticate headlessly.

Managing accounts after that, from the CLI

Once you hold a valid session (interactive login, or an existing service account), up0 service-accounts manages the rest.

Create

terminal
up0 --profile kind service-accounts create \
  --name "1652 docs example" \
  --username "docs-1652-example" \
  --role editor
output
✓ Service account "1652 docs example" created.

  UP0_CLIENT_ID=docs-1652-example
  UP0_CLIENT_SECRET=Sgabvr…redacted…   (shown once, store it in your secrets manager)

The secret is shown exactly once, here and nowhere else. There is no way to retrieve it again, only to rotate it for a new one.

List

terminal
up0 --profile kind service-accounts list
output
                                Service Accounts
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ id                     ┃ name              ┃ role   ┃ created_at             ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ e98dcedb-a82a-4bfa-84… │ 1652 docs example │ editor │ 2026-09-16T13:27:33.0… │
└────────────────────────┴───────────────────┴────────┴────────────────────────┘

--output json returns the full, untruncated id and every field.

Rotate

terminal
up0 --profile kind service-accounts rotate e98dcedb-a82a-4bfa-843a-34b133ab9175 --yes
output
✓ Secret rotated. The prior secret no longer works.

  UP0_CLIENT_ID=docs-1652-example
  UP0_CLIENT_SECRET=Yqnwbv…redacted…   (shown once, store it in your secrets manager)

Rotating invalidates the previous secret immediately; anything still using it starts failing to authenticate.

Revoke

terminal
up0 --profile kind service-accounts revoke e98dcedb-a82a-4bfa-843a-34b133ab9175 --yes
output
✓ Service account e98dcedb-a82a-4bfa-843a-34b133ab9175 revoked.

A revoked account can no longer authenticate at all and stops appearing in service-accounts list, though it is not deleted outright.

All four commands, and the console panel they mirror, are gated to the Owner role and server-enforced, not just hidden in the UI.

What a service account can call

Whatever its bound role permits, exactly like a human member with that role: an Editor-bound service account can create and edit resources but not manage billing or delete the organization; a Viewer-bound one is read-only. There is no separate, narrower permission model for machine identities; the same role catalog in Roles and permissions applies.

Ingestion tokens are a different thing

A service account authenticates a caller against the API (creating monitors, reading issues, running CLI commands). It is not how telemetry gets in; that uses a separate ingestion token created with up0 tokens create, unrelated to any member or service account identity. See the ingestion guides under Instrument your app for that flow.

On this page