netbox-oidc-group-sync¶
A python-social-auth pipeline step that syncs NetBox
Django groups and is_superuser status from an OIDC groups claim.
The gap¶
NetBox Community ships two independent group-sync code paths under netbox.authentication:
RemoteUserBackend.configure_groups()implements dynamic, claim-based group sync (with optional auto-create) plus superuser evaluation fromREMOTE_AUTH_SUPERUSER_GROUPS-- but it's only ever invoked fromRemoteUserBackend.authenticate(), Django's HTTP-header remote-auth path (aREMOTE_USERheader set by an upstream reverse proxy). It is never reached by a social-auth/OIDC login.user_default_groups_handler, the step actually wired intoSOCIAL_AUTH_PIPELINEfor social-auth backends (including OIDC), only assigns a staticREMOTE_AUTH_DEFAULT_GROUPSlist. It never reads a claim and never touchesis_superuser.
So if you're using social_core.backends.open_id_connect.OpenIdConnectAuth (or another social-auth OIDC
backend) as your NetBox login method, setting REMOTE_AUTH_GROUP_SYNC_ENABLED / AUTO_CREATE_GROUPS /
SUPERUSER_GROUPS in your NetBox configuration has no effect whatsoever -- those settings are consumed
exclusively by the header-based backend, which OIDC logins never touch.
NetBox Labs' Enterprise product solves this with a proprietary pipeline step
(nbc_auth_extensions.azure_authentication.azuread_map_groups), documented as
Entra ID-specific and Enterprise-only.
The fix¶
sync_groups closes that gap for Community: dropped into SOCIAL_AUTH_PIPELINE in place of
user_default_groups_handler, it re-implements configure_groups()'s logic against the OIDC response
instead of an HTTP header, reusing the exact same REMOTE_AUTH_* settings NetBox already defines. No new
configuration surface, no fork of NetBox itself.
See Installation to get it running, and Configuration for the settings it reads.
A NetBox-specific gotcha¶
NetBox 4.x doesn't use Django's stock django.contrib.auth.models.Group -- it defines its own
users.models.Group, a completely separate model/table, and User.groups points there instead.
sync_groups imports from users.models, not django.contrib.auth.models; getting this wrong produces a
TypeError: Field 'id' expected a number but got <Group: ...> at login time, since Django's M2M machinery
can't resolve a pk from an instance of the wrong model. Also unlike Django's stock auth.Group-based
AbstractUser, NetBox's User model has no is_staff field at all -- only is_superuser.