Skip to content

Add SCIM provisioning sample for User Management - #389

Closed
StuFrankish wants to merge 1 commit into
mainfrom
sf/scim-provisioning-sample
Closed

StuFrankish wants to merge 1 commit into
mainfrom
sf/scim-provisioning-sample

Conversation

@StuFrankish

Copy link
Copy Markdown
Member

Adds IdentityServer/v8/UserManagement/ScimProvisioning, an Aspire sample that connects a simulated upstream directory (SCIM source) to IdentityServer with User Management inbound SCIM (destination). Companion to the UM inbound SCIM docs (products-private#3040).

Projects

  • ScimProvisioning.AppHost starts Mailpit, IdentityServer and Directory. Directory waits for IdentityServer and receives its URL as both the token authority and the SCIM base URL.
  • ScimProvisioning.IdentityServer uses DefaultScimUserSchema, EnableScim/MapScim, ScimResources and the clients scim-provisioner (scim) and scim-reader (scim.read). It has read-only users and groups views and OTP sign-in for provisioned users only.
  • ScimProvisioning.Directory has seeded employees and departments, and a hand-written SCIM client using Duende.AccessTokenManagement. It covers discovery, user create, update, deactivate and delete, groups and membership, Bulk with bulkId references, and userName eq reconcile. This is not a Duende feature; outbound SCIM is not on the roadmap.

Behaviour notes

  • active is stored profile data only. A deactivated user can still sign in.
  • OTP sign-in never creates a profile. It attaches the email OTP address to the existing SCIM profile and refuses conflicting authenticator ownership. It issues a session only when the authenticated subject equals the provisioned profile's subject.

Workarounds for 2.0.0-preview.6 (documented in README)

  • Configure<JwtBearerOptions>("DuendeScimBearer", o => o.Authority = issuer): without it, valid scim tokens get 401 invalid_token.
  • IUserProfileAdmin.TryGetAsync(userName, value) returns null for SCIM-provisioned profiles, so login uses a filtered QueryAsync.
  • The destination does not return externalId, so the Directory matches by userName and group displayName.

Verification

  • dotnet build ScimProvisioning.slnx passes.
  • Ran without a license key. IdentityServer logs development-mode license warnings, including "SCIM 2.0 Inbound is being used but no Duende license is configured". Authenticated SCIM calls still succeed.
  • Auth: no token write returns 401, a scim.read write returns 403, a scim.read read returns 200 and a scim write returns 201.
  • Every Directory action succeeds, and the Bulk group membership resolves bulkId references.
  • Provisioned Casey, set active=false and signed in via Mailpit OTP. The session sub equals Casey's SCIM id and no extra profile was created. An unknown userName is refused.

- Add Aspire AppHost wiring Mailpit, IdentityServer (SCIM destination) and a simulated upstream Directory (SCIM source)
- Enable inbound SCIM with DefaultScimUserSchema, SCIM API resource and scopes, and client credentials clients
- Configure the DuendeScimBearer authority directly to work around late signing-key discovery in 2.0.0-preview.6
- Add Directory actions for discovery, user create, update, deactivate and delete, groups and membership, Bulk with bulkId references, and filter reconcile
- Add OTP sign-in limited to SCIM-provisioned profiles, with a subject equality check before issuing a session
- Show stored users, groups and the active attribute as read-only data
- Add README and register the projects in samples.slnx
@StuFrankish
StuFrankish deleted the sf/scim-provisioning-sample branch October 19, 2026 13:10
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.

1 participant