Skip to content

feat(scim): Add SCIM /Users endpoints - #2747

Open
xlgmokha wants to merge 1 commit into
masterfrom
scim/3-users
Open

feat(scim): Add SCIM /Users endpoints#2747
xlgmokha wants to merge 1 commit into
masterfrom
scim/3-users

Conversation

@xlgmokha

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Feature. Add SCIM endpoints for core User schema.

What is the current behavior?

These endpoints do not exist yet.

What is the new behavior?

Adds:

Method Path Description
GET /scim/v2/Users List / paginate / sort SCIM users
GET /scim/v2/Users/{id} Get a specific SCIM user
POST /scim/v2/Users Create a new SCIM user
PUT /scim/v2/Users/{id} Replace a specific SCIM user
DELETE /scim/v2/Users/{id} Delete (soft) a specific SCIM user
GET /scim/v2/ResourceTypes/{id} Resource Type endpoint for User resource
GET /scim/v2/Schemas/{id} Schema description endpoint for User schema

Additional context

  • The /Users endpoints authenticate with a bearer SCIM token. Tokens are stored hashed in the new scim_tokens table, are revocable (revoked_at) and expirable (expires_at), and resolve to an sso_provider_id that scopes every query to a single tenant.
  • The new /ResourceTypes/{id} and /Schemas/{id} routes are discovery metadata and are unauthenticated, consistent with the existing /ServiceProviderConfig, /ResourceTypes, and /Schemas endpoints.
  • All SCIM routes stay behind the existing requireScimServerEnabled gate.
  • New migrations add the scim_users and scim_tokens tables. A user's SCIM payload is stored as a JSONB resource column and deletes are soft using deleted_at.
  • PATCH and filtering are not implemented yet. List rejects any filter parameter.

Extracted from #2731

@xlgmokha
xlgmokha changed the base branch from master to scim/2-core August 26, 2026 00:59
@xlgmokha xlgmokha self-assigned this Aug 26, 2026
@xlgmokha
xlgmokha force-pushed the scim/3-users branch 2 times, most recently from 6e4416d to edff202 Compare August 26, 2026 22:33
@xlgmokha
xlgmokha force-pushed the scim/2-core branch 2 times, most recently from f689fc8 to fec7a7d Compare August 26, 2026 23:29
@xlgmokha
xlgmokha force-pushed the scim/3-users branch 2 times, most recently from 3538a0b to 77782ab Compare August 26, 2026 23:31
@xlgmokha
xlgmokha force-pushed the scim/3-users branch 2 times, most recently from 4709682 to e114c8e Compare August 27, 2026 16:17
@xlgmokha
xlgmokha force-pushed the scim/2-core branch 2 times, most recently from a9ac782 to 316aa74 Compare August 27, 2026 17:11
@xlgmokha
xlgmokha force-pushed the scim/3-users branch 3 times, most recently from eb969a8 to 86c6ef9 Compare August 28, 2026 15:45
@xlgmokha
xlgmokha marked this pull request as ready for review August 28, 2026 16:39
@xlgmokha
xlgmokha requested a review from a team as a code owner August 28, 2026 16:39
Comment thread internal/api/scim/user_repository.go
Comment thread internal/api/scim/user_repository.go
@xlgmokha
xlgmokha force-pushed the scim/3-users branch 2 times, most recently from 7294ee5 to e6690b1 Compare August 28, 2026 16:58
Comment thread internal/api/scim/user_repository.go
@xlgmokha xlgmokha closed this Aug 28, 2026
@xlgmokha
xlgmokha deleted the scim/3-users branch August 28, 2026 23:05
@xlgmokha xlgmokha reopened this Aug 28, 2026
@xlgmokha
xlgmokha marked this pull request as draft August 28, 2026 23:06
@xlgmokha
xlgmokha marked this pull request as ready for review September 1, 2026 17:26
Comment thread internal/models/scim_token.go

@annabkr annabkr left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: could we break this up for easier review? I find Claude is pretty good at doing that, if it feels tedious to do yourself

@hf hf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, some minor clarifications not blocking from my POV.

Comment thread internal/api/scim/core/attribute.go Outdated
Comment on lines +5 to +16
Name string `json:"name"`
Type AttributeType `json:"type"`
MultiValued bool `json:"multiValued"`
Description string `json:"description"`
Required bool `json:"required"`
CanonicalValues []string `json:"canonicalValues,omitempty"`
CaseExact bool `json:"caseExact"`
Mutability Mutability `json:"mutability"`
Returned Returned `json:"returned"`
Uniqueness Uniqueness `json:"uniqueness"`
ReferenceTypes []ReferenceType `json:"referenceTypes,omitempty"`
SubAttributes []*Attribute `json:"subAttributes,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't all of these have omitempty?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't all of these have omitempty?

RFC 7643 says:

Unlike other core resources, the "Schema" resource MAY contain a complex object within a sub-attribute, and all attributes are REQUIRED unless otherwise specified.

So I opted to not add the omitempty so that they get the default zero values which would be false for all booleans.

field required
name Y
name Y
type Y
multiValued Y
description Y
required Y
caseExact Y
mutability Y
returned Y
uniqueness Y
canonicalValues N
referenceTypes N
subAttributes N

Comment thread internal/api/scim/core/kind.go Outdated
Comment on lines +85 to +87
if values.Get("sortBy") != "" {
return SortAscending, nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is ?sortBy (without =true) handled here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is ?sortBy (without =true) handled here?

I think this will return as a default sort order and then the default sorting will kick in. I'll double check though.

Comment thread internal/models/sso.go
@xlgmokha
xlgmokha changed the base branch from scim/2-core to master September 3, 2026 17:52
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