Implement SCIM 2.0 provisioning so identity providers can manage users and groups in Flagsmith automatically, without relying on login-time sync.
Core concept
Flagsmith exposes a SCIM 2.0 API at /api/v1/scim/v2/ that identity providers (Okta, Azure AD, OneLogin) call to create, update, and remove users and groups. Each Flagsmith organisation can have one SCIM configuration, which consists of a bearer token tied to that organisation. The token is hashed at rest and shown once on creation.
The implementation uses django-scim2 with custom adapters that map SCIM operations to existing Flagsmith models. No new fields are added to FFAdminUser or UserPermissionGroup — existing fields are mapped directly:
| SCIM field |
Flagsmith field |
User id |
FFAdminUser.uuid |
User userName |
FFAdminUser.email |
User name.givenName |
FFAdminUser.first_name |
User name.familyName |
FFAdminUser.last_name |
User active |
derived from org membership |
Group id |
UserPermissionGroup.id (PK) |
Group displayName |
UserPermissionGroup.name |
Group externalId |
UserPermissionGroup.external_id |
Deprovisioning (DELETE or PATCH active: false) calls FFAdminUser.remove_organisation(), which removes org membership, all project/environment permissions, and all group memberships within that org. User data (audit log entries, change request history) is preserved.
The SCIM module lives in flagsmith-private and is conditionally loaded at startup, following the pattern used by SAML and LDAP. Plan gating restricts SCIM to Enterprise subscriptions. No feature flag is needed.
The default raw SQL filter strategy in django-scim2 is replaced with an ORM-based filter using scim2-filter-parser's Django Q object transpiler. This ensures org-scoped tenant isolation happens in SQL, not in Python.
The docs-first spec is at #7139.
Implement SCIM 2.0 provisioning so identity providers can manage users and groups in Flagsmith automatically, without relying on login-time sync.
Core concept
Flagsmith exposes a SCIM 2.0 API at
/api/v1/scim/v2/that identity providers (Okta, Azure AD, OneLogin) call to create, update, and remove users and groups. Each Flagsmith organisation can have one SCIM configuration, which consists of a bearer token tied to that organisation. The token is hashed at rest and shown once on creation.The implementation uses django-scim2 with custom adapters that map SCIM operations to existing Flagsmith models. No new fields are added to FFAdminUser or UserPermissionGroup — existing fields are mapped directly:
idFFAdminUser.uuiduserNameFFAdminUser.emailname.givenNameFFAdminUser.first_namename.familyNameFFAdminUser.last_nameactiveidUserPermissionGroup.id(PK)displayNameUserPermissionGroup.nameexternalIdUserPermissionGroup.external_idDeprovisioning (DELETE or PATCH
active: false) callsFFAdminUser.remove_organisation(), which removes org membership, all project/environment permissions, and all group memberships within that org. User data (audit log entries, change request history) is preserved.The SCIM module lives in flagsmith-private and is conditionally loaded at startup, following the pattern used by SAML and LDAP. Plan gating restricts SCIM to Enterprise subscriptions. No feature flag is needed.
The default raw SQL filter strategy in django-scim2 is replaced with an ORM-based filter using scim2-filter-parser's Django Q object transpiler. This ensures org-scoped tenant isolation happens in SQL, not in Python.
The docs-first spec is at #7139.