Skip to content

Custom SCIM attribute mapping

Custom SCIM attribute mapping

Each provisioning connection carries an attribute_mapping that decides how a platform user's attributes are rendered into the SCIM 2.0 User resource pushed to the downstream app. A mapping entry is scimPath => sourceKey: the value at sourceKey in the platform snapshot is written to the SCIM attribute scimPath.

The default

When a connection's mapping is empty, Cbox\Id\Provisioning\Support\AttributeMapping::DEFAULTS applies — the attributes every SCIM app expects:

[
    'userName'       => 'email',
    'displayName'    => 'name',
    'name.formatted' => 'name',
    'emails'         => 'email',
]

active is never mapped from source data; it is set by the lifecycle operation itself (create/update → true, deactivate → false).

Supplying your own

Pass a mapping at registration. Dot-notation targets a SCIM sub-attribute; the emails target is expanded to the RFC 7643 multi-valued form [{value, primary: true, type: work}]:

app(ProvisioningConnections::class)->register(
    // …
    attributeMapping: [
        'userName'         => 'email',
        'name.givenName'   => 'first_name',
        'name.familyName'  => 'last_name',
        'displayName'      => 'name',
        'emails'           => 'email',
    ],
);

The sourceKeys must exist in the platform snapshot. The framework's snapshot is built from the Subject value object (email, name); a host with richer user data binds its own Cbox\Id\Identity\Contracts\Subjects resolver so those keys are present in the snapshot.

Enterprise extension

An inline enterprise source value is emitted under the RFC 7643 §4.3 Enterprise User extension URN, with the extension URN added to the resource's schemas:

// source snapshot: ['email' => …, 'enterprise' => ['department' => 'Engineering']]
// →
[
    'schemas' => [
        'urn:ietf:params:scim:schemas:core:2.0:User',
        'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User',
    ],
    'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => ['department' => 'Engineering'],
    // …
]

Deeper control

For behaviour the mapping table can't express (computed values, per-app quirks in how PATCH bodies are framed), rebind the Cbox\Id\Provisioning\Contracts\ScimClient contract with your own decorator over HttpScimClient, or bind a different ProvisioningService — both are resolved from the container, contracts-first.