Identity providers¶
What Microsoft Entra ID, Okta and other identity providers send, and what to map for each. The documentation is the reference for the mapping attributes.
Unmapped attributes¶
The schemas publish only the mapped attributes (Limits). For an attribute that the class does not map:
| Request | Result |
|---|---|
A POST or PUT body, or the value of a PATCH operation without path |
The server drops the attribute. |
A PATCH path to the attribute or sub-attribute, for example title or name.formatted |
400 invalidPath. The other operations of the request are not applied either. |
A PATCH path with a type that has no slot, for example emails[type eq "other"].value when only the work slot is mapped |
The bundle drops the element. |
Thus map each attribute of the attribute mapping of the identity provider, or remove the attribute from that mapping.
Microsoft Entra ID¶
Connection¶
Create a non-gallery enterprise application. In Provisioning > New configuration, set:
| Field | Value |
|---|---|
| Tenant URL | The base URL, for example https://example.com/scim/v2. Optional: append ?aadOptscim062020 for the RFC 7644 PATCH format. The server accepts both formats. On-demand provisioning ignores the flag. |
| Secret Token | A token of access_tokens (Configuration). Entra sends Authorization: Bearer <token>. |
Microsoft supports the Secret Token for non-gallery applications. For OAuth 2.0 client credentials or Workload Identity Federation, use another token handler (Firewall).
Test Connection queries a user by a random GUID. The server answers 200 with an empty ListResponse.
Microsoft Entra ID setup gives each step in the admin center.
User attributes¶
The Microsoft SCIM tutorial gives these user mappings as an example. The Attribute mapping page of the application shows its real list. Map each row of that list, or delete the row in Entra.
| Entra attribute | SCIM path | Mapping |
|---|---|---|
user-PrincipalName |
userName |
#[ScimAttribute('userName')] |
mailNickname |
externalId |
#[ScimAttribute('externalId')] |
IsSoftDeleted |
active |
#[ScimAttribute('active', default: true)] |
displayName |
displayName |
#[ScimAttribute('displayName')] |
givenName |
name.givenName |
#[ScimAttribute('name.givenName')] |
surname |
name.familyName |
#[ScimAttribute('name.familyName')] |
jobTitle |
title |
#[ScimAttribute('title')] |
mail |
emails[type eq "work"].value |
#[ScimAttribute('emails[type eq "work"].value', primary: true)] |
proxy-Addresses |
emails[type eq "other"].Value |
#[ScimAttribute('emails[type eq "other"].value')] |
telephone-Number |
phoneNumbers[type eq "work"].value |
#[ScimAttribute('phoneNumbers[type eq "work"].value', primary: true)] |
mobile |
phoneNumbers[type eq "mobile"].value |
#[ScimAttribute('phoneNumbers[type eq "mobile"].value')] |
Facsimile-TelephoneNumber |
phoneNumbers[type eq "fax"].value |
#[ScimAttribute('phoneNumbers[type eq "fax"].value')] |
streetAddress |
addresses[type eq "work"].streetAddress |
#[ScimAttribute('addresses[type eq "work"].streetAddress', primary: true)] |
postalCode |
addresses[type eq "work"].postalCode |
#[ScimAttribute('addresses[type eq "work"].postalCode')] |
physical-Delivery-OfficeName |
addresses[type eq "other"].Formatted |
#[ScimAttribute('addresses[type eq "other"].formatted')] |
department |
enterprise department |
#[ScimAttribute('department')] |
employeeId |
enterprise employeeNumber |
#[ScimAttribute('employeeNumber')] |
manager |
enterprise manager |
#[ScimAttribute('manager')] on private ?self $manager |
- Write the sub-attribute in schema spelling:
value,formatted. - Microsoft's known issues say that Entra processes only the
worktype ofaddresses,emailsandphoneNumbers. The tutorial also mapsmobile,faxandother. The provisioning logs show what arrives. - Entra finds users with
userName eq "..."andexternalId eq "..."filters. Both are Fields, so both filter. - Entra does not provision passwords. Do not map
passwordfor Entra. - Entra sends no null values. A value that is cleared in Entra stays in the application.
Group attributes¶
| Entra attribute | SCIM path | Mapping |
|---|---|---|
displayName |
displayName |
#[ScimAttribute('displayName')] |
members |
members |
#[ScimAttribute('members[type eq "User"]')] on a collection of users |
objectId |
externalId |
#[ScimAttribute('externalId')] |
- Entra matches groups with
displayName eq "...". Microsoft requires a uniquedisplayName. The bundle publishes it as unique by default, so a duplicate name gives 409uniqueness. - A member id that no mapped collection finds gives 400
invalidValue. When a group has groups as members, also mapmembers[type eq "Group"](References and members).
Deprovisioning¶
| Event in Entra | Request |
|---|---|
| User unassigned, out of scope, disabled or soft-deleted | PATCH active false. Entra sends "False" without the flag. |
| User restored | PATCH active true. |
| User hard-deleted, 30 days after the soft delete or by a purge | DELETE, when the Delete target action is on. Not for a user that was unassigned before: Entra no longer manages it. |
| Group deleted or unassigned | DELETE. Microsoft's group sequence ends with a DELETE, but does not name the event that sends it. |
Microsoft requires that GET and filters return a user whether or not the user is active. Do not hide inactive users (Soft delete).
Failures¶
Entra retries a failed object 6, 12 and 24 hours after the failure, then each day for 28 days. Entra puts the job in quarantine for invalid credentials, for a 404 where it expects 200, and from 5,000 failures when more than 40 percent of the events fail or more than 40,000 events fail. Failed references, for example a manager or a group member, do not count toward these limits, but all failures count toward a limit of 60,000. A quarantined job runs less often, down to once a day. After four weeks in quarantine, Entra disables the job. An unmapped PATCH path fails each cycle, so map the attributes before you start provisioning.
Okta¶
Connection¶
| Setting | Value |
|---|---|
| SCIM connector base URL | The base URL, for example https://example.com/scim/v2. Okta rejects a base URL with _. |
| Authentication Mode | HTTP Header, with a token of access_tokens in Authorization. The token extractor reads the token with and without Bearer. |
| Unique identifier field for users | userName. Okta finds an existing user with userName eq "...". |
| To App | Create Users, Update User Attributes, Deactivate Users. Sync Password only when the class maps password. |
Okta setup gives each step in the Admin Console.
User attributes¶
Okta requires userName, name.givenName, name.familyName, emails and active. A create request also has
displayName, locale, externalId, password and groups.
| SCIM path | Mapping | Notes |
|---|---|---|
userName |
#[ScimAttribute('userName')] |
Required. |
name.givenName |
#[ScimAttribute('name.givenName')] |
Required. |
name.familyName |
#[ScimAttribute('name.familyName')] |
Required. |
emails[type eq "work"].value |
#[ScimAttribute('emails[type eq "work"].value', primary: true)] |
Required. |
active |
#[ScimAttribute('active', default: true)] |
Required. |
externalId |
#[ScimAttribute('externalId')] |
The Okta user id, for example 00ujl29u0le5T6Aj10h7. |
displayName |
#[ScimAttribute('displayName')] |
|
locale |
#[ScimAttribute('locale')] |
Optional. Dropped when unmapped. |
password |
#[ScimAttribute('password', converter: HashPassword::class)] |
Okta sends a password on create also without password sync, unless Set password when creating new users is off. Map it only for password sync (Password). Dropped when unmapped. |
groups |
readOnly. The server ignores it. |
Attributes that you add to the Okta app profile arrive with the same rule as Unmapped attributes.
Requests¶
- A profile update is a GET, then a PUT of the GET document with the changed values. A PUT drops unmapped attributes, so they never fail a request.
- New OIN integrations activate, deactivate and sync passwords with PATCH. Integrations made with the App Integration Wizard, now the Classic experience, use PUT for each update.
- Okta never deletes a user. It sends
activefalse. Okta sends nothing for a suspended user. Do not hide inactive users. - Group Push creates a group with POST. New OIN integrations change a group with PATCH, integrations made with the App Integration Wizard with PUT. Okta deletes a group only when the administrator unlinks it and selects the delete option.
Other identity providers¶
| Identity provider | What to check |
|---|---|
| JumpCloud | Activation creates, reads, updates and deletes a test user. JumpCloud finds a user by email, then by userName. The default mapping also sends addresses, phoneNumbers of type work, and the enterprise organization, costCenter, department and employeeNumber. |
| OneLogin | The administrator writes the JSON template of the user. Map each attribute of the template. |
| PingOne | The administrator writes the matching filter, for example userName Eq "%s". A filter on an unmapped attribute gives 400 invalidFilter. |
Sources¶
Read on 2026-11-05, 2026-11-06 and 2026-11-07.