Documentation menu

Zitadel

Your login and grant store — the identity Atrium runs on.

Capability: identity · Identity. This is a core capability: the platform asks it questions, so exactly one connected instance is marked Primary and answers. The first instance you enable becomes Primary automatically; a second one never steals the role.

Vendor site · Vendor docs

Configure Zitadel in Atrium → (admins only)

Setup

The management credential Atrium uses to provision grants, reconcile group membership and read projects. This is the write side of Atrium → Zitadel — never the login/OIDC client secret.

  1. Create a service user. In Zitadel, create a machine (service) user that represents Atrium, e.g. "atrium-management". Open the console page ↗
  2. Grant it the right manager role. Assign IAM_OWNER at the instance level (needed for Action Targets & Executions and cross-org reads). An ORG_OWNER token also works for org-scoped calls and goes in the Service-admin field.
  3. Generate a Personal Access Token. On the service user → Personal Access Tokens → New. Copy the token value once and paste it into the IAM token field below. (A service-account key JSON is the last-resort fallback.)

What you paste back into Atrium

In order, the values the steps above produce:

  1. IAM token (PAT) — or an Org-Owner Service-admin token

How it works

This is the WRITE side of Atrium to Zitadel, and only that. The login path (which OIDC client users sign in through) is deploy-time config read by NextAuth before any database or session exists, so it is deliberately not editable here: a database-backed login secret would be a lockout waiting to happen. What this credential does is provision: it turns Atrium's model of who belongs to which group into Zitadel grants.

What Atrium does, and when

When this happensAtrium does this
A person is granted access to an app, or joins a group that confers itCreates or updates the user grant on the app's Zitadel project with the resulting roles.
A person loses that accessRemoves the grant. Sign-in for that app fails at the identity provider from then on, not just in Atrium's own UI.
An admin opens an app or group screenReads projects, roles and existing grants so the screen shows Zitadel's actual state rather than Atrium's cached opinion of it.
A reconcile pass runs over a groupFans out into one management call per member. The 30-second resolver cache exists specifically so this fan-out does not re-read the credential row per call.

Guarantees and limits

  • The three credential fields are alternatives, not a set. Exactly one is needed: the IAM token is preferred, then the service-admin token, then the service-account key JSON. A row with none of them reads as unconfigured rather than half-wired.
  • Instance-level operations (Action Targets and Executions, cross-org reads) require IAM_OWNER. An ORG_OWNER token is enough for org-scoped work (grants, projects, users) and nothing more.
  • Identity is a core capability: exactly one connected instance is Primary and answers.

What "Test connection" proves

Performs an authenticated read against the management API with the token as supplied. A pass proves the token is valid and has at least read scope. It does not prove the token can write grants: an under-scoped ORG_OWNER token passes the probe and then fails on the first instance-level call.

Troubleshooting

SymptomCauseFix
Grants are created but the person still cannot sign in.The app's Zitadel project has projectRoleCheck (or hasProjectCheck) set in a way the grant does not satisfy, or the user's session predates the grant.Check the project's settings in Zitadel, then have the person sign out of Atrium properly (or use a private window). Re-logging in at Zitadel alone does not refresh an Atrium cookie.
Everything worked, then every management call started failing at once.The PAT expired or was revoked on the service user.Generate a new Personal Access Token on the same service user and paste it here. No redeploy needed.
Zitadel bills far more API calls than expected.A reconcile path is issuing one call per member instead of a bulk read.A code-side concern, not a config one: reconcilers should read a group's members with one bulk-index call rather than one call per member.

Required scopes

Grant the credential exactly these scopes; they are the least-privilege set the connector needs:

  • IAM_OWNER (iamToken)
  • ORG_OWNER (serviceAdminToken)

Configuration fields

FieldTypeRequiredNotes
iamToken
IAM token
password
secret
noPAT / service-account token with the IAM_OWNER role (instance scope: Action Targets & Executions). Maps to ZITADEL_IAM_TOKEN. Preferred token for all management calls.
serviceAdminToken
Service admin token
password
secret
noOrg Owner token — fallback for org-scoped calls (grants, projects, users). Maps to ZITADEL_SERVICE_ADMIN_TOKEN.
serviceAccountKey
Service-account key (JSON)
password
secret
noOptional machine-key JSON ({type,keyId,key,userId}) for the JWT-assertion flow. Last-resort fallback when no bearer token is set. Maps to ZITADEL_SERVICE_ACCOUNT_KEY.

Operating notes

  • Secret fields are encrypted at rest (AES-256-GCM) and never returned to the client. Editing an instance and leaving a secret field masked keeps the stored value.
  • Adding a connector from the marketplace creates a disabled, credential-less instance ("Added, not yet connected"); it does nothing until an admin opens it, pastes credentials, and enables it.
  • Use Test connection on the instance page before enabling: it performs a read-only probe with the credentials you entered.
  • Connector credentials live in the Atrium database, not in container env vars; changing them here takes effect without a redeploy (within the resolver's 30-second cache).