<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc SYSTEM "rfc2629.dtd">
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" docName="draft-poreddy-scim-role-assignment-00" category="std" ipr="trust200902" submissionType="IETF">

  <front>
    <title abbrev="SCIM RoleAssignment">SCIM RoleAssignment Draft Specification v0.1</title>

    <author fullname="Prithvi Poreddy">
      <organization>Independent</organization>
      <address>
        <postal>
          <country>US</country>
        </postal>
        <email>prithvikrishnab4u@gmail.com</email>
      </address>
    </author>

    <date month="September" year="2025"/>

    <area>Applications and Real-Time (ART)</area>
    <workgroup>SCIM</workgroup>

    <abstract>
      <t>SCIM 2.0 defines "roles" and "entitlements" attributes on the User resource,
      but it lacks a standardized way to bind roles to specific scopes such as projects,
      tenants, or groups. This gap forces organizations to rely on group sprawl or
      non-standard encodings, preventing true interoperability. This document introduces
      a new SCIM resource type, <spanx style="emph">RoleAssignment</spanx>, which models
      scoped role bindings as first-class records, enabling portable provisioning,
      lifecycle governance, and compliance visibility.</t>
    </abstract>
  </front>

  <middle>

    <section title="Introduction">
      <section title="Problem Statement">
        <t>The SCIM protocol <xref target="RFC7643"/>
        <xref target="RFC7644"/>
 defines the User and
        Group resources and allows global roles to be attached to Users via the "roles" attribute.
        However, the specification does not provide a standardized way to associate roles with
        specific scopes such as projects, tenants, or device groups.</t>

      <t>This limitation prevents SCIM from modeling the most common real-world requirement:
        assigning different roles to the same identity in different contexts.</t>

      <t>For example, consider a user named Alice:</t>
      <figure>
        <artwork><![CDATA[
User: Alice
 +-- Global Role: Power User
 +-- Project A: Maintainer
 +-- Project B: Developer
 +-- Project C: ReadOnly
]]>        </artwork>
      </figure>

      <t>Today, there is no interoperable SCIM method to represent Alice's per-project role
        bindings. Current workarounds include creating Groups for every {scope x role} combination,
        which leads to group sprawl and poor interoperability, or embedding scope names into free-form
        role strings, which are not machine-readable or portable.</t>

      <t>These limitations are visible in real-world SCIM implementations:
        GitLab <xref target="GITLAB-SCIM"/>
, Tanium <xref target="TANIUM-RBAC"/>
, and scenarios in
        Microsoft Entra ID <xref target="AZURE-SCIM"/>
.</t>
</section>

<section title="Proposed Solution">
  <t>This document introduces a new SCIM 2.0 resource, <spanx style="emph">RoleAssignment</spanx>,
        which makes scoped role bindings a first-class concept. Each RoleAssignment explicitly links a
        subject (for example, User), a scope (for example, Project), and a role (for example, Developer).
        Optional metadata such as validity periods, source system, and approver information enable
        lifecycle management and governance.</t>

  <t>By standardizing RoleAssignments:
    <list style="symbols">
      <t>Identity Providers can provision scoped roles in a portable way.</t>
      <t>Service Providers can expose and consume these assignments consistently.</t>
      <t>Auditors and governance systems can query "who has what role in which scope."</t>
    </list>
  </t>
</section>
</section>

<section title="Requirements Language">
<t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
      "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
      "OPTIONAL" in this document are to be interpreted as described in
      BCP 14 <xref target="RFC2119"/>
<xref target="RFC8174"/>
 when, and only when,
      they appear in all capitals, as shown here.</t>
</section>

<section title="Overview">
<t>The RoleAssignment resource complements existing SCIM resources. Whereas the User.roles
      attribute provides only coarse global roles, RoleAssignment expresses who (subject) has what role
      in which scope. This allows interoperable provisioning of scoped role bindings.</t>
</section>

<section title="Schema">

<section title="Resource Type">
<figure>
  <artwork type="json"><![CDATA[
{
  "name": "RoleAssignment",
  "endpoint": "/RoleAssignments",
  "schema": "urn:ietf:params:scim:schemas:core:2.0:RoleAssignment",
  "schemaExtensions": []
}
]]>  </artwork>
</figure>
</section>

<section title="Attributes (Top-Level)">
<t>The RoleAssignment resource defines the following top-level attributes.</t>
<table anchor="attr-main">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>id</td>
      <td>string</td>
      <td>yes</td>
      <td>no</td>
      <td>readOnly</td>
      <td>Provider-assigned unique identifier.</td>
    </tr>
    <tr>
      <td>externalId</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Client-supplied correlation id.</td>
    </tr>
    <tr>
      <td>subject</td>
      <td>complex</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>The subject receiving the role.</td>
    </tr>
    <tr>
      <td>scope</td>
      <td>complex</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>The scope where the role applies.</td>
    </tr>
    <tr>
      <td>role</td>
      <td>complex</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>The role granted within the scope.</td>
    </tr>
    <tr>
      <td>priority</td>
      <td>integer</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Conflict resolution (higher wins). Default 0.</td>
    </tr>
    <tr>
      <td>grant</td>
      <td>complex</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Assignment metadata (source, reason, approver).</td>
    </tr>
    <tr>
      <td>validity</td>
      <td>complex</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Validity window in UTC.</td>
    </tr>
    <tr>
      <td>status</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readOnly</td>
      <td>Computed lifecycle status.</td>
    </tr>
  </tbody>
</table>

<t>
  <spanx style="emph">Priority usage guidance:</spanx> When multiple active assignments exist for the same
        subject and scope, the assignment with the highest priority takes precedence. If priorities are equal,
        implementation-defined resolution rules apply.</t>
</section>

<section title="subject Sub-Attributes">
<table anchor="attr-subject">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>value</td>
      <td>string</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Identifier of the subject.</td>
    </tr>
    <tr>
      <td>$ref</td>
      <td>reference</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>URI to the subject resource, when available.</td>
    </tr>
    <tr>
      <td>type</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Subject type. Standard: "User", "Group". "ServiceAccount" MAY be used. Vendor-specific types SHOULD use prefixes.</td>
    </tr>
  </tbody>
</table>
</section>

<section title="scope Sub-Attributes">
<table anchor="attr-scope">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>type</td>
      <td>string</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Scope type. Common: "project", "tenant", "organization", "application", "environment".</td>
    </tr>
    <tr>
      <td>value</td>
      <td>string</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Provider-meaningful identifier of the scope.</td>
    </tr>
    <tr>
      <td>$ref</td>
      <td>reference</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>URI to the scope resource, if available. Optional when scope is opaque.</td>
    </tr>
  </tbody>
</table>
</section>

<section title="role Sub-Attributes">
<table anchor="attr-role">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>name</td>
      <td>string</td>
      <td>yes</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Display name of the role.</td>
    </tr>
    <tr>
      <td>value</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Stable identifier for the role.</td>
    </tr>
    <tr>
      <td>$ref</td>
      <td>reference</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>URI to a role catalog entry, if available. Providers with catalogs SHOULD include $ref for discovery.</td>
    </tr>
  </tbody>
</table>

<t>
  <spanx style="emph">Role Discovery Guidance:</spanx> Since role.$ref is optional, servers
  <bcp14>SHOULD</bcp14> support filtering on role and scope to enable discovery, for example:</t>
<figure>
  <artwork><![CDATA[
GET /RoleAssignments?attributes=role,scope&filter=scope.type eq "project"
]]>  </artwork>
</figure>

<t>Providers that expose a role catalog MAY align discovery with the SCIM Roles and
        Entitlements approach <xref target="SCIM-ROLES-ENTITLEMENTS"/>
.</t>
</section>

<section title="grant Sub-Attributes">
<table anchor="attr-grant">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>source</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Originating system or process.</td>
    </tr>
    <tr>
      <td>reason</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Human-readable justification.</td>
    </tr>
    <tr>
      <td>approver</td>
      <td>string</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Approver identifier or reference.</td>
    </tr>
  </tbody>
</table>
</section>

<section title="validity Sub-Attributes">
<table anchor="attr-validity">
  <thead>
    <tr>
      <th>Attribute</th>
      <th>Type</th>
      <th>Req</th>
      <th>Multi</th>
      <th>Mutability</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>validFrom</td>
      <td>dateTime</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>Start of validity window (UTC).</td>
    </tr>
    <tr>
      <td>validTo</td>
      <td>dateTime</td>
      <td>no</td>
      <td>no</td>
      <td>readWrite</td>
      <td>End of validity window (UTC).</td>
    </tr>
  </tbody>
</table>
</section>

<section title="status Semantics">
<t>The "status" attribute is <bcp14>readOnly</bcp14> and computed using the following rules:</t>
<list style="numbers">
  <t>If the referenced subject is inactive: status = "suspended".</t>
  <t>If current time &lt; validity.validFrom: status = "pending".</t>
  <t>If current time &gt; validity.validTo: status = "expired".</t>
  <t>Otherwise: status = "active".</t>
</list>
<t>Special cases:
  <list style="symbols">
    <t>If validity.validFrom is null, assignment is immediately eligible.</t>
    <t>If validity.validTo is null, assignment does not expire.</t>
    <t>If explicitly revoked via DELETE or PATCH: status = "revoked".</t>
  </list>
</t>
<t>Required status values:
  <list style="symbols">
    <t>"active": assignment is currently effective.</t>
    <t>"expired": validity window has ended.</t>
    <t>"pending": assignment created but not yet effective.</t>
    <t>"suspended": subject inactive or assignment temporarily disabled.</t>
    <t>"revoked": assignment was explicitly withdrawn.</t>
  </list>
</t>
</section>

<section title="Complete Example">
<figure>
  <artwork type="json"><![CDATA[
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:RoleAssignment"],
  "id": "assignment-12345",
  "externalId": "ext-assign-001",
  "subject": {
    "value": "alice@company.com",
    "$ref": "https://example.com/scim/v2/Users/alice",
    "type": "User"
  },
  "scope": {
    "type": "project",
    "value": "web-app-proj",
    "$ref": null
  },
  "role": {
    "name": "Developer",
    "value": "developer",
    "$ref": null
  },
  "priority": 100,
  "grant": {
    "source": "HR-System",
    "reason": "New team member onboarding",
    "approver": "manager@company.com"
  },
  "validity": {
    "validFrom": "2025-09-01T00:00:00Z",
    "validTo": "2026-09-01T00:00:00Z"
  },
  "status": "active"
}
]]>  </artwork>
</figure>
</section>
</section>

<section title="Operations">
<t>
<list style="symbols">
  <t>
    <spanx style="emph">Create (POST):</spanx> Servers <bcp14>MUST</bcp14> validate subject, scope, and role.</t>
  <t>
    <spanx style="emph">Replace (PUT):</spanx> Missing required attributes cause 400 Bad Request.</t>
  <t>
    <spanx style="emph">Patch (PATCH):</spanx>
    <bcp14>MUST</bcp14> be supported; invalid states <bcp14>SHOULD</bcp14> be rejected.</t>
  <t>
    <spanx style="emph">Delete (DELETE):</spanx> Removes assignment and <bcp14>SHOULD</bcp14> revoke permissions.</t>
  <t>
    <spanx style="emph">Filter (GET):</spanx>
    <bcp14>MUST</bcp14> support filters on subject, scope, role.</t>
  <t>
    <spanx style="emph">Pagination/Sorting:</spanx>
    <bcp14>MUST</bcp14> support startIndex and count; <bcp14>SHOULD</bcp14> support sorting.</t>
  <t>
    <spanx style="emph">Bulk:</spanx>
    <bcp14>MAY</bcp14> be supported. Clients <bcp14>SHOULD</bcp14> use externalId for idempotency.</t>
</list>
</t>

<section title="Common Query Patterns">
<figure>
  <artwork><![CDATA[
- User's assignments:
  GET /RoleAssignments?filter=subject.value eq "alice@company.com"

- Scope permissions:
  GET /RoleAssignments?filter=scope.value eq "project-x"

- Role discovery within a scope type:
  GET /RoleAssignments?attributes=role&filter=scope.type eq "project"

- Expiring access before a date/time:
  GET /RoleAssignments?filter=validity.validTo le "2025-12-31T23:59:59Z"
]]>  </artwork>
</figure>
</section>
</section>

<section title="Error Handling">
<t>
<list style="symbols">
  <t>400 Invalid Value for malformed attributes or invalid validity windows.</t>
  <t>404 Not Found for unknown subject, scope, or role references.</t>
  <t>409 Conflict for duplicate active assignments.</t>
  <t>412 Precondition Failed for ETag mismatches on conditional updates.</t>
</list>
</t>
<t>Error responses <bcp14>SHOULD</bcp14> include "detail" and "scimType" per <xref target="RFC7644"/>
.</t>

<section title="Error Example: Invalid Validity Window">
<figure>
  <artwork type="json"><![CDATA[
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  "status": "400",
  "scimType": "invalidValue",
  "detail": "validity.validFrom must be before validity.validTo"
}
]]>  </artwork>
</figure>
</section>

<section title="Error Example: Conflicting Assignment">
<figure>
  <artwork type="json"><![CDATA[
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
  "status": "409",
  "scimType": "uniqueness",
  "detail": "Active assignment exists for subject 'alice@company.com' with role 'admin' in scope 'project-x'"
}
]]>  </artwork>
</figure>
</section>
</section>

<section title="Backward Compatibility">
<t>Providers <bcp14>MAY</bcp14> continue to expose global roles via User.roles and coarse-grained
      membership via Groups. Providers <bcp14>SHOULD</bcp14> offer mapping guidance between legacy models
      and RoleAssignments. Dual-writing (maintaining both representations) is <bcp14>RECOMMENDED</bcp14>
      during migration.</t>
</section>

<section title="Security Considerations">
<t>
<list style="symbols">
  <t>RoleAssignment creation and modification are privileged operations.</t>
  <t>Servers <bcp14>MUST</bcp14> validate references to prevent privilege escalation.</t>
  <t>Lifecycle events <bcp14>SHOULD</bcp14> be logged with actor and justification.</t>
  <t>Replay and bulk abuse <bcp14>MUST</bcp14> be mitigated with rate limiting and idempotency.</t>
</list>
</t>
</section>

<section title="Privacy Considerations">
<t>RoleAssignments may expose organizational structures and access patterns.
      Sensitive metadata <bcp14>SHOULD</bcp14> follow least-privilege disclosure.</t>
</section>

<section title="IANA Considerations">
<t>This specification requests registration of the following SCIM schema:</t>
<figure>
<artwork><![CDATA[
URN: urn:ietf:params:scim:schemas:core:2.0:RoleAssignment
Specification: this document
Contact: IETF SCIM Working Group
Change Controller: IESG

Experimental namespace MAY also be used:
URN: urn:ietf:params:scim:schemas:extension:role:1.0:RoleAssignment
]]></artwork>
</figure>
<t>URNs are assigned and interpreted in accordance with <xref target="RFC8141"/>
.</t>
</section>

<section title="Conformance">
<section title="Server">
<t>
  <list style="symbols">
    <t>
      <bcp14>MUST</bcp14> implement RoleAssignment and advertise it in /ResourceTypes.</t>
    <t>
      <bcp14>MUST</bcp14> validate subject, scope, and role.</t>
    <t>
      <bcp14>MUST</bcp14> enforce authorization on RoleAssignment operations.</t>
    <t>
      <bcp14>MUST</bcp14> support GET, POST, PUT, PATCH, DELETE, filtering.</t>
    <t>
      <bcp14>SHOULD</bcp14> support sorting and bulk operations.</t>
  </list>
</t>
</section>
<section title="Client">
<t>
  <list style="symbols">
    <t>
      <bcp14>MUST</bcp14> construct RoleAssignments per schema.</t>
    <t>
      <bcp14>MUST</bcp14> process error responses per <xref target="RFC7644"/>
.</t>
    <t>
      <bcp14>SHOULD</bcp14> use externalId for idempotency.</t>
    <t>
      <bcp14>SHOULD</bcp14> honor ETag preconditions.</t>
  </list>
</t>
</section>
</section>

</middle>

<back>
<references title="Normative References">
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3339.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7643.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.7644.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8141.xml"/>
</references>

<references title="Informative References">
<reference anchor="GITLAB-SCIM">
<front>
  <title>Set up SCIM for GitLab groups</title>
  <author fullname="GitLab Documentation"/>
  <date month="September" year="2025"/>
</front>
<seriesInfo name="Online" value="accessed September 2025"/>
<format type="HTML" target="https://docs.gitlab.com/administration/settings/scim_setup/"/>
</reference>

<reference anchor="TANIUM-RBAC">
<front>
  <title>Role-based access control in the Tanium Console</title>
  <author fullname="Tanium Documentation"/>
  <date month="September" year="2025"/>
</front>
<seriesInfo name="Online" value="accessed September 2025"/>
<format type="HTML" target="https://help.tanium.com/bundle/ug_console_cloud/page/platform_user/console_roles.html"/>
</reference>

<reference anchor="AZURE-SCIM">
<front>
  <title>Issue provisioning multiple roles to a SCIM app</title>
  <author fullname="Microsoft Learn"/>
  <date month="September" year="2025"/>
</front>
<seriesInfo name="Online" value="accessed September 2025"/>
<format type="HTML" target="https://learn.microsoft.com/en-us/answers/questions/1632657/issue-provisioning-multiple-roles-to-a-scim-app"/>
</reference>

<reference anchor="SCIM-ROLES-ENTITLEMENTS">
<front>
  <title>Roles and Entitlements Extension for SCIM</title>
  <author fullname="Christian Zollner"/>
  <date month="June" year="2025"/>
</front>
<seriesInfo name="Internet-Draft" value="draft-zollner-scim-roles-entitlements-extension-02"/>
<format type="HTML" target="https://datatracker.ietf.org/doc/draft-zollner-scim-roles-entitlements-extension/"/>
</reference>
</references>

<section title="Change Log">
<section title="draft-poreddy-scim-role-assignment-00">
<t>Initial version. Defines RoleAssignment schema, attributes, and operations.
        Adds priority, complete example, error examples, and query patterns. Includes error handling,
        backward compatibility, and IANA registration. Updates BCP14 boilerplate; replaces non-ASCII;
        converts ASCII tables to RFCXML tables; updates Roles/Entitlements reference to -02; cites RFC8141.</t>
</section>
</section>

<section title="Author's Address">
<t>Prithvi Poreddy&lt;br/&gt;
      Email: &lt;prithvikrishnab4u@gmail.com&gt;</t>
</section>
</back>

</rfc>