SCIM Provisioning Bugs: roles mapping sends empty object, wrong type value, and primary as string instead of boolean

Boris Gusarov 0 Reputation points
2026-06-05T10:14:05.1033333+00:00

Hello Entra Support,

I am writing to report three bugs I have encountered while configuring SCIM provisioning for our integration. All relate to the roles attribute mapping behaving differently from what the Entra UI previews and what the SCIM 2.0 spec defines.


Bug 1 — Constant mapped to a sub-attribute filter path is sent as an empty object

Configuration

  • Mapping type: Constant
  • Constant value: "member"
  • Target attribute: roles[type eq "role"].value
  • Attribute type: String
  • Referenced object: None

Expected behavior

The Entra provisioning UI previews the mapping correctly:

| Target attribute name | Source attribute value | Expression | Original target attribute value | Modified target attribute value |

| roles[type eq "role"].value | "member" | "member" | | member |

Based on this, the SCIM PATCH request sent to our endpoint should include:


{

  "op": "replace",

  "path": "roles[type eq \"role\"].value",

  "value": "member"

}

Actual behavior

The actual SCIM PATCH request received by our endpoint contains an empty object instead of the configured string:


"Operations": [

  {

    "op": "replace",

    "path": "roles[type eq \"role\"].value",

    "value": {}

  }

]

This is an inconsistency between what the provisioning UI previews and what is actually sent to the SCIM endpoint, suggesting a serialization bug specific to sub-attribute path expressions using filter notation.


Bug 2 — Standard roles attribute mapping sends a hardcoded internal type value instead of the configured one

As a workaround for Bug 1, I attempted to use Entra's standard roles attribute mappings instead of the custom filter path approach.

Configuration

  • roles[primary eq "True"].type → constant value: "role"
  • roles[primary eq "True"].value → constant value: "admin"

Expected behavior

The SCIM PATCH payload should reflect the configured values:


"roles": [

  {

    "type": "role",

    "primary": true,

    "value": "admin"

  }

]

Actual behavior

The value field is correctly provisioned as "admin", but the type field is overridden with an internal Entra value instead of the configured constant:


"roles": [

  {

    "type": "WindowsAzureActiveDirectoryRole",

    "primary": true,

    "value": "admin"

  }

]

The type value "WindowsAzureActiveDirectoryRole" appears to be a hardcoded internal Entra designation that is sent regardless of what is configured in the attribute mapping. This makes the standard roles mapping unusable for integrations that require a specific, application-defined type value (such as "role" per RFC 7643).


Bug 3 — primary is sent as a string "True" instead of a boolean true, on PATCH action breaking subsequent GET deserialization

Expected behavior

Per SCIM 2.0 (RFC 7643 §2.3.5), the primary sub-attribute of a multi-valued attribute is defined as type boolean. The PATCH payload should serialize it accordingly:


"roles": [

  {

    "primary": true,

    "value": "admin"

  }

]

Actual behavior

Entra sends primary as the string "True" instead of the boolean true:


"roles": [

  {

    "primary": "True",

    "value": "admin"

  }

]

This type mismatch has a cascading effect: Entra itself cannot deserialize the user on the subsequent GET call, which means the provisioning cycle breaks end-to-end — not just on our side but within Entra's own flow.

I am aware of the SCIM compatibility flags documented at https://learn.microsoft.com/en-us/entra/identity/app-provisioning/application-provisioning-config-problem-scim-compatibility#flags-to-alter-the-scim-behavior, which are intended to address exactly this type of serialization issue. I have applied the relevant flag, but the behavior remains unchanged — primary continues to be sent as the string "True".


Summary

All three approaches to configuring roles provisioning from Entra are broken:

  1. The custom filter path approach (roles[type eq "role"].value) sends {} instead of the configured string.
  2. The standard roles mapping approach ignores the configured type constant and substitutes a hardcoded internal value.
  3. The primary sub-attribute is sent as a string "True" instead of a boolean true, causing deserialization failures on Entra's own subsequent GET calls — and the documented compatibility flag does not resolve this.

This leaves no working path to correctly provision SCIM roles attributes from Entra to our endpoint.


Environment

  • Identity Provider: Microsoft Entra ID
  • Integration type: SCIM 2.0
  • Affected operation: User provisioning (PATCH)

Please let me know if you need additional logs, tenant details, or a HAR trace to investigate further.

Thank you.

Microsoft Security | Microsoft Entra | Microsoft Entra ID

1 answer

Sort by: Oldest
  1. AI answer

    2026-06-05T10:14:48.86+00:00

    The described behavior aligns with current limitations and known behaviors of Microsoft Entra’s SCIM provisioning implementation rather than issues that can be fully remediated by configuration alone.

    Key points from documented behavior:

    1. Roles provisioning and complex attributes
      • Roles are provisioned using complex, multivalued attributes and special expressions such as AppRoleAssignmentsComplex and AssertiveAppRoleAssignmentsComplex.
      • Custom complex and multivalued attributes are supported, but there are limits: flowing data to complex attributes with three or more subattributes is not supported, and Microsoft Entra ID does not have many complex data structures to pull data from in these cases.
      • For roles, documentation explicitly recommends using AppRoleAssignmentsComplex or AssertiveAppRoleAssignmentsComplex expressions to map Entra app role assignments into SCIM roles, rather than arbitrary custom filter-path mappings on roles[type eq "..."]....
    2. id vs value and role identity
      • For SCIM roles, id is not required; value can be used as the role identifier.
      • A feature flag is available to adjust behavior around the id attribute for roles, but documentation notes that relying solely on value is not always sufficient when multiple roles share the same name/identifier. In some cases, id must be used.
    3. SCIM PATCH behavior and type handling
      • Microsoft Entra’s SCIM implementation historically had non‑compliant PATCH behavior and introduced a feature flag (aadOptscim062020) to make PATCH requests more SCIM‑compliant (e.g., correct casing of op, boolean vs string values, and multi‑attribute replace/remove behavior).
      • The flag affects:
        • Requests made to disable users (active boolean handling)
        • Requests to add a single‑value string attribute
        • Requests to replace multiple attributes
        • Requests to remove a group member
      • This behavior change is currently only available when using the flag and does not work with on‑demand provisioning.
    4. Entra as SCIM client and requirements
      • The provisioning service is designed to support SCIM 2.0, but the SCIM compliance article documents that there are known issues and flags to alter behavior.
      • For multivalued complex attributes, the type subattribute values must be unique, and custom complex attributes are constrained.

    How this maps to the three reported issues:

    1. Constant mapped to roles[type eq "role"].value resulting in {}
      • The documentation does not describe or guarantee support for arbitrary constant mappings to filtered sub‑attribute paths on complex multivalued attributes like roles[type eq "role"].value.
      • It instead documents supported patterns using AppRoleAssignmentsComplex / AssertiveAppRoleAssignmentsComplex for roles.
      • Given the stated limitations on complex attributes and the absence of documented support for this specific pattern, the behavior observed (empty object in value) is consistent with an unsupported or partially supported mapping scenario.
    2. roles[primary eq "True"].type being overridden with WindowsAzureActiveDirectoryRole
      • The roles provisioning guidance focuses on mapping Entra app role assignments into SCIM roles and notes that Entra uses its own role constructs.
      • The documentation does not describe a supported scenario where the type subattribute of roles is fully controlled by a constant mapping; instead, it emphasizes mapping Entra app roles via the provided complex expressions.
      • The observed type value WindowsAzureActiveDirectoryRole is consistent with Entra’s internal representation of app roles and is not contradicted by the documentation.
    3. primary sent as string instead of boolean
      • The SCIM compliance article explicitly documents that a feature flag (aadOptscim062020) changes PATCH behavior to be more SCIM‑compliant, including:
        • Using lowercase op values
        • Using proper JSON types (e.g., active as a boolean instead of a string)
      • The examples show the difference for active, but the same flag governs general PATCH compliance behavior.
      • The documentation also notes that this feature flag does not apply to on‑demand provisioning and that the new behavior will become the default over time.

    Recommended path based on documented guidance:

    1. Use the supported roles expressions
      • Configure roles provisioning using AppRoleAssignmentsComplex or AssertiveAppRoleAssignmentsComplex as documented in the “Provisioning a role to a SCIM app” section, rather than custom constant mappings on roles[type eq ...].
      • These expressions are the supported way to map Entra app roles into SCIM roles and are designed to handle complex role structures and PATCH semantics.
    2. Use the SCIM compliance feature flag
      • Ensure the SCIM compliance flag (aadOptscim062020) is applied to the SCIM tenant URL as documented under “Flags to alter the SCIM behavior”.
      • Be aware that this flag does not affect on‑demand provisioning and that behavior differences may persist there until the new behavior becomes the default.
    3. Align SCIM endpoint implementation with Entra’s expectations
      • Implement SCIM roles such that:
        • id is not required for roles if value is sufficient, but support id when needed.
        • Multivalued complex attributes (like roles) enforce unique type values.
      • Ensure the endpoint accepts PATCH requests in the form Entra sends (including AppRoleAssignmentsComplex / AssertiveAppRoleAssignmentsComplex payloads) and returns valid SCIM responses.

    If the behavior persists when using AppRoleAssignmentsComplex or AssertiveAppRoleAssignmentsComplex with the SCIM compliance flag enabled, the next step is to capture the exact PATCH and GET traffic and open a support case so that the SCIM provisioning service team can investigate, as this goes beyond what is covered in the documented behavior.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.