Status: Locked 2026-05-01. This page is the canonical reference for
how users, groups, and identity flow through every blackreset application.
Changes require an explicit decision-log entry under
Migration / Decisions log.
User.uuid field, e.g.5d9caf1d-4826-44d1-acaf-a5221abc03b4) is the canonical identifierThe Active Directory at xio.bio is not the IDP for apps. It exists
solely for Windows-domain operations:
| Use case | Backed by |
|---|---|
| Domain-Join of Windows workstations | AD |
| RDP authentication into domain-joined hosts | AD |
| Group-Policy distribution (GPOs) | AD |
| Printer / share authentication on the Windows side | AD |
| Anything else (web app login, OIDC, group claims for apps) | Authentik |
Account count post-cleanup is small (a handful of humans + service
accounts). See Migration / AD cleanup 2026-04-30.
AD -> Authentik (read-only). Authentik's existing LDAP-Source
ldap-xio-bio (slug ldap-xio-bio) periodically pulls users and groups
from the AD DC and mirrors them as Authentik users with path=users/.
| Mapping | Detail |
|---|---|
ms-samaccountname -> Authentik username |
sAMAccountName drives the Authentik login name |
AD objectGUID -> Authentik attribute (informational) |
not used as the canonical id — Authentik mints its own UUID |
| AD groups -> Authentik groups | mirrored, but not used for app authorization |
References: inventory/authentik/standard.md, inventory/authentik/report.md.
No Authentik -> AD sync. The Authentik LDAP outpost (see
/migration/authentik-ldap-outpost-2026)
serves apps that need an LDAP server but does not write back to AD. AD
remains a one-way upstream source, never a downstream replica.
| Scenario | Where to create | Why |
|---|---|---|
| Default new human | Authentik directly (users/... or users/People/IO/, etc.) |
Authentik is the IDP; AD does not need to know about app-only users |
| User who needs Windows-domain (RDP / Workstation / Domain-Join / GPOs) | AD first; LDAP-source sync surfaces them in Authentik on the next pull | Domain functions require an AD object; Authentik picks them up automatically |
| Service account for an app | Authentik (type=service-account or type=internal) |
Same logic — apps go through Authentik |
Never create a user directly in an app's local DB if it could come from
Authentik. See "What we never do" below.
Two strict tiers, separated by purpose:
| Group type | Lives in | Examples | Used for |
|---|---|---|---|
| App-Gruppen | Authentik only | grp-nextcloud-user, grp-gitlab-admin, grp-wiki-admin, grp-portainer-admin |
App-level authorization (admin role, allowed-to-login binding, etc.) |
| Domain-Gruppen | AD (mirrored read-only into Authentik) | Domain Admins, g-pc-workstation, g-rdp-allowed |
Windows-domain operations only — irrelevant for app authorization |
App-Gruppen are never in AD. Domain-Gruppen flow AD -> Authentik but
should not be referenced as authorization gates by any app.
Every app stores its own internal user-id, but the identity link back
to Authentik follows a fixed pattern:
| App | Auth backend(s) | Canonical app uid | Identity-link mechanism |
|---|---|---|---|
| Nextcloud | user_oidc + user_ldap (both via Authentik) |
oc_users.uid = Authentik UUID (dashed) |
OIDC: sub claim (sub_mode=user_uuid on svc-nextcloud-oidc). LDAP: oc_ldap_user_mapping.directory_uuid = Authentik User.uid (64-char hex), owncloud_name = Authentik UUID (dashed) — pre-populated for the 10 migrated users. See /migration/nc-authentik-2026. |
| GitLab | OmniAuth OIDC + LDAP (both via Authentik) | users.id (GitLab numeric) |
OIDC: Identity row with provider='openid_connect', extern_uid = Authentik UUID (uid_field='sub' in gitlab.rb). LDAP: Identity row with provider='ldapmain', extern_uid = DN. Pre-created for known users; auto-link for new users via omniauth_auto_link_ldap_user=true. See /migration/gitlab-authentik-2026. |
| Wiki.js | OIDC | wiki.users.providerId = Authentik UUID |
OIDC sub; group claim groups -> wiki group grp-wiki-admin -> admin role |
| Mailcow-SOGo | OIDC | varies (per-mailbox) | OIDC sub, see per-app page (TBD) |
| Portainer | OIDC | Portainer internal user id | OIDC sub, group claim drives role |
| Proxmox | OIDC | PVE realm user | OIDC sub, see per-app page (TBD) |
Per-app detail pages live under /services/{app} and /access/authentik/{app}.
Never edit a user in Authentik to "match" what an app expects.
Apps adapt to the IDP, not the other way around. If an app's matcher
is too strict, fix the app config or pre-populate its mapping table.
Never reset master-password / encryption-IV columns of password-derivation
apps during user-uid migrations. Specifically:
oc_otpmanager_settings.password, .ivoc_passwords_keychain.dataoc_twofactor_totp_secrets.secretThese are derived from a per-user master password that is separate
from the NC login password. Overwriting them silently destroys all
encrypted-at-rest data — no master-password reset will recover it.
See the OTP-Manager incident in
/migration/nc-authentik-2026.
Never create users directly in an app's local DB if they could come
from Authentik. The only exceptions are documented per-app local
accounts (e.g. NC outdoor user — local-only, not OIDC/LDAP-bound).
Never bind an LDAP outpost application via backchannel_providers:.
The outpost only reads the provider: field. See gotcha 5 in
/migration/authentik-ldap-outpost-2026.
Never set authorization_flow = default-provider-authorization-implicit-consent
on an LDAP provider. The implicit-consent flow is OAuth-shaped and
breaks every LDAP bind. Use default-authentication-flow. Same page,
gotcha 1.
| Topic | Page |
|---|---|
| Nextcloud OIDC + LDAP migration record | /migration/nc-authentik-2026 |
| GitLab OIDC + LDAP migration record | /migration/gitlab-authentik-2026 |
| Authentik LDAP outpost runbook | /migration/authentik-ldap-outpost-2026 |
| AD cleanup record | /migration/ad-cleanup-2026 |
| Authentik standard / conventions | inventory/authentik/standard.md |
| Authentik full-state report | inventory/authentik/report.md |
| Group inventory and conventions | /access/groups |
| Naming convention | /standards/naming-convention |