Skip to content

Authorization (Authz)

Zitadel says who a user is; authz says what they can do. Authz is a ConnectRPC service (platform/authz) that stores every role grant in the acl table of the environment's database. Nexus calls it on every request that needs a permission check.

See Dev → Authz → Model for the schema and the evaluation rules. This page is the operator's view.

Roles

Defined in nexus (internal/authz/authz.go, RoleSeeds) and written to authz by SeedRoles on every nexus start.

Id Role Target Grants
1 ORG_OWNER portal:org Every action on the org: devices, console, audit, managing people
7 ORG_MEMBER portal:org Read and write the org's gateways. No console, no audit, cannot grant or revoke
2 DEVICE_OWNER portal:device Read, write and transfer one device
3 PLATFORM_ADMIN portal:system Every action platform-wide, including the admin pages
4 SUPPORT portal:org or portal:device Read, write, console and audit, without being a member
5 SUPPORT_ADMIN as SUPPORT, plus portal:system Support, plus device:manage (assigning devices out of the holding zone)
6 PARTNER portal:segment Read and write one managed segment, across customers. No console

Before granting anything:

  • ORG_OWNER includes a root console on every device in the org. It is the org wildcard, not a "manage the team" role. Give ORG_MEMBER to people who operate gateways but should not have a shell or manage access.
  • SUPPORT_ADMIN is not a platform admin. Platform admin is specifically the wildcard action on portal:system; SUPPORT_ADMIN holds only device:manage there and does not see the admin pages.
  • Support roles are not membership. Only ORG_OWNER and ORG_MEMBER appear in an org's member list. Support grants authorise work on a customer's resources without showing up in that customer's Members tab.
  • PARTNER has no org or device rows. It is granted per segment with PortalGatewayService.GrantSegmentAccess, by platform admins only; the portal has no screen for it.

Who can grant what

Enforced in nexus (requireGrantAuthority), for granting and revoking alike:

Grant Who may give or remove it
Anything on portal:system, and any SUPPORT, SUPPORT_ADMIN or PLATFORM_ADMIN grant Platform admins only
ORG_OWNER / ORG_MEMBER / DEVICE_OWNER on an org Platform admins, and holders of the org wildcard (ORG_OWNER)
A role on a device Platform admins, holders of write or transfer on that device, and owners of the org the device belongs to

Inviting (creating a Zitadel account with PortalUsersService.Invite) is allowed only to a caller who could then grant something: a platform admin, an org owner, or a holder of write/transfer on a device. ORG_MEMBER, PARTNER and users with no grant are refused.

Creating an organization is platform-admin only (PortalOrgService.CreateOrganization). The org is created with owner system and no grants; its first owner is invited from the Team page.

Granting and revoking

Use the portal: Team for people in an organization, Admin > Organizations for creating one. The step-by-step is in Onboarding a customer from the portal.

The portal calls PortalOrgService.AssignPermission and RevokePermission. Going through the API also applies validateRoleTarget, which refuses a role paired with a target it has no actions for (for example DEVICE_OWNER on an organization). Such a row written directly into acl is stored and listed, and authorises nothing, because evaluation joins acl to role_actions on (role_id, target).

The first platform admin

The one grant that needs SQL, because nobody can grant it yet. Run it against the environment's database:

-- subject_id is the raw Zitadel sub, not an email or a local user id.
INSERT INTO acl (subject_id, role_id, target, target_id)
VALUES ('<zitadel_sub>', 3, 'portal:system', '*')
ON CONFLICT DO NOTHING;

target_id must be *. After that, further platform admins are granted from the portal (Team > My access > Add Permission, role Platform admin).

"No organization yet" on screen

The user is signed in and holds no grant. Signing in provisions nothing: there is no personal organization and no automatic ORG_OWNER. Org access is an acl row keyed on the raw Zitadel sub; it is not derived from Zitadel's own organizations or roles. Grant the user a role (see above), then have them sign out and back in.

Why not Zitadel's own roles?

Zitadel's role model (per user × project × org) does not map onto per-device or per-segment grants. Keeping the ACL in the environment's own database lets an authorization decision happen without a round trip to Zitadel on every RPC.