Skip to content

Conversation

@Bewinxed
Copy link
Collaborator

@Bewinxed Bewinxed commented Dec 31, 2025

What kind of change does this PR introduce?

Feature - adds SCIM v2 provisioning support for enterprise SSO providers

This is a complete, general implementation inspired by the needs of this PR #2115

What is the current behavior?

Currently there's no way for identity providers (Okta, Azure AD, OneLogin, etc.) to automatically provision and deprovision users. Admins have to manually manage user accounts when employees join or leave, which is error-prone and doesn't scale for enterprise customers.

What is the new behavior?

Adds full SCIM v2 (RFC 7644) support, allowing identity providers to:

  • User provisioning: Automatically create users when added to the IdP
  • User updates: Sync profile changes (name, email) from IdP
  • User deprovisioning: Soft-delete users via ban when removed from IdP (preserves data, terminates sessions)
  • Group management: Create/update/delete groups and manage group membership

Endpoints added:

  • GET/POST /scim/v2/Users - list and create users
  • GET/PUT/PATCH/DELETE /scim/v2/Users/{id} - manage individual users
  • GET/POST /scim/v2/Groups - list and create groups
  • GET/PUT/PATCH/DELETE /scim/v2/Groups/{id} - manage individual groups
  • Discovery endpoints: /scim/v2/ServiceProviderConfig, /scim/v2/Schemas, /scim/v2/ResourceTypes

Authentication: Bearer token per SSO provider (stored as bcrypt hash)

Filtering: Full RFC 7644 filter support using the scim2/filter-parser library - supports eq, ne, co, sw, ew, pr, gt, ge, lt, le operators with and/or/not logic.

IdP compatibility: Tested with Azure AD quirks (booleans as strings, case-insensitive displayName uniqueness).

Additional context

I tried my best to make the implementation fit within the current tenant/user model instead of new tables for everything, adding schema changes only when necessary.

Some compliance work might be needed for other nuances with other SCIM providers (I've tested Microsoft Azure).

Deviations from RFC 7643

Some deviations from the RFC for SCIM v2 were done that relates to Supabase Auth:

  • Email is REQUIRED, as required by our auth model.
  • Deprovisioning uses soft-delete via Ban with reason (the RFC leaves this implementation to the imlementer).
  • Bulk operations not supported, yet in the initial implementation.

New dependencies

  • github.com/scim2/filter-parser/v2 - RFC 7644 SCIM filter parsing

Schema Changes

  • sso_providers gets 2 new columns: scim_enabled (boolean), scim_bearer_token_hash (text)
  • scim_groups - stores SCIM groups per SSO provider
  • scim_group_members - junction table for group membership
  • Bulk operations not supported in initial release

Testing

All tests were based on the assumptions that the Azure Validation Tool expects, currently all passing.

@Bewinxed Bewinxed force-pushed the bewinxed/add-scim-v2 branch from 158c1ad to f514de5 Compare January 19, 2026 10:08
- Add FindUsersByProviderWithFilter for SCIM user listing
- Add FindSCIMGroupsBySSOProviderWithFilter for group listing
- Make external_id nullable, add case-insensitive displayName index
- Validate user belongs to SSO provider before adding to group
Replace string-based error comparison with proper typed error pattern
following existing codebase conventions in models/errors.go.
Remove CountSCIMGroupsBySSOProvider and FindSCIMGroupsBySSOProvider
which were superseded by FindSCIMGroupsBySSOProviderWithFilter.
Export UserBelongsToSSOProvider from models package and use it as
single source of truth. API layer retains thin wrapper for convenience.
Remove duplicate SCIMFilterResult type from api package in favor of
models.SCIMFilterClause. Remove now-unnecessary toModelFilterClause
conversion function.
- Remove duplicate SCIMErrorResponse and NewSCIMError from scim_types.go
  (use apierrors.SCIMHTTPError instead)
- Remove duplicate SCIMSchemaError constant (already defined in apierrors)
- Fix error wrapping in applySCIMUserPatch for Ban/Logout operations
- Fix error wrapping in scimDeleteUser for Logout operation
- Wrap validateEmail error in SCIM format in scimCreateUser
@Bewinxed Bewinxed force-pushed the bewinxed/add-scim-v2 branch from f514de5 to 7a60f1b Compare January 19, 2026 10:13
@Bewinxed Bewinxed marked this pull request as ready for review January 19, 2026 10:15
@Bewinxed Bewinxed requested a review from a team as a code owner January 19, 2026 10:15
@Bewinxed Bewinxed force-pushed the bewinxed/add-scim-v2 branch from 72e8e4d to 8450879 Compare January 19, 2026 10:18
@coveralls
Copy link

coveralls commented Jan 19, 2026

Pull Request Test Coverage Report for Build 21133681412

Details

  • 986 of 1726 (57.13%) changed or added relevant lines in 15 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.8%) to 68.013%

Changes Missing Coverage Covered Lines Changed/Added Lines %
internal/api/errors.go 4 6 66.67%
internal/api/scim_helpers.go 111 115 96.52%
internal/api/scim_types.go 16 22 72.73%
internal/models/errors.go 2 8 25.0%
internal/models/sso.go 23 36 63.89%
internal/api/apierrors/apierrors.go 27 45 60.0%
internal/models/scim_group.go 85 125 68.0%
internal/models/user.go 35 75 46.67%
internal/api/ssoadmin.go 0 72 0.0%
internal/api/scim_filter.go 28 148 18.92%
Totals Coverage Status
Change from base Build 21130794887: -0.8%
Covered Lines: 15811
Relevant Lines: 23247

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants