ndovuscim

SCIM SPEC · RFC 7644

RFC 7644

The protocol: endpoints and methods, the discovery contract, the filter grammar with its unresolved errata, PATCH and bulk semantics, the error tables, and the examples the RFC published broken.

Proposed Standard · September 2015 · 89 pagesupdated by RFC 9865 and RFC 9967
01 · The wire in one view

Every request is HTTP against a Base URI with JSON bodies typedapplication/scim+json. The Base URI MUST NOT contain a query string, because clients append paths and query parameters to it; it MAY carry a version prefix such as /v2/, which MUST sit immediately before the resource endpoint (Sections 1.3 and 3.13). Protocol messages carry their own schema URIs under urn:ietf:params:scim:api:, and these message schemas are not discoverable through /Schemas, which lists the resource schemas from RFC 7643 (Section 3.1). Validation is receiver-side: a request is interpreted in the context of the server's own schema, with no document-validation pass a client could pre-check against.

Table 1 assigns the methods, and one row carries the rule integrations break most often: PUT replaces a resource and "MUST NOT be used to create new resources". An upsert attempt over PUT is out of contract by definition; creation is POST's job.

The endpoint set: /Users, /Groups, and /Me for resources;/ServiceProviderConfig, /ResourceTypes, and /Schemas for discovery; /Bulk and [prefix]/.search for the two composite operations (Section 3.2). Extended resources SHOULD pluralize the schema's resource name by appending an "s", and the same paragraph concedes the rule is ambiguous ("Person" is legitimately "Persons" or "People"), which is the doorway to the discovery contract below.

02 · The discovery contract

Section 4 fixes three discovery endpoints: /ServiceProviderConfig for capabilities,/ResourceTypes for the resource-to-endpoint bindings, and /Schemas for the attribute definitions. The discovery rule clients SHOULD follow is ResourceType-based: read/ResourceTypes, take each type's endpoint member, and never guess a plural form. The RFC's own pluralization guidance is declared ambiguous in the same section that states it, so the discovery endpoint is the contract and the convention is a hint.

The trio's names carry their own errata story. Verified erratum 8365 corrected Section 4's description of/ResourceTypes from "endpoints" to the singular "endpoint", matching the single-valuedendpoint member in RFC 7643 Section 6. The opposite question on/ServiceProviderConfig is open: the RFC text and its examples use the singular, while the provisioning ecosystem's documentation and major implementations (Facebook, Salesforce, Slack are named in the erratum) use the plural /ServiceProviderConfigs. Reported erratum4978 records the conflict, reported 2017-03-24 and still in the Reported bucket, so it is unresolved as of 2026-11-01; a client that probes exactly one spelling will fail against part of the ecosystem. The discovery trio is what theschema explorer renders its context from.

Versioning and concurrency close the contract. The version prefix is optional, discovered preferably over hard-coded (Section 3.13). Resources version by HTTP ETag (Section 3.14): weak validators are allowed, conditional requests ride If-Match, and a stale version yields 412. The meta.versionmember MUST equal the ETag, which is the consistency rule between RFC 7643's resource representation and this document's concurrency model.

03 · Creating and reading

Creation is POST to the resource endpoint with the mutability rules in force: read-only attributes are ignored, and a client clears values by sending null for a single-valued attribute or[] for a multi-valued one (Section 3.3). Success is 201 with a Location header and a body whose meta.location matches. A duplicate conflict is 409 with scimTypeuniqueness in the body.

Retrieval of a known resource is GET by id, 200 back. Querying (Section 3.4.2) wraps results in the ListResponse schema, urn:ietf:params:scim:api:messages:2.0:ListResponse:totalResults is REQUIRED, Resources is REQUIRED when totalResultsis non-zero, and startIndex and itemsPerPage are REQUIRED on partial results. An empty match is a success: 200 with totalResults of 0. A query against the server root that would return too much SHALL be rejected 400 with scimType tooMany. Theattributes and excludedAttributes parameters trim the returned representation and accept full schema-URI-prefixed paths (Section 3.10). POST Search at[prefix]/.search moves the same parameters into a SearchRequest body, which is also the mitigation for the filter-in-URL logging problem the security section describes.

04 · The filter grammar

Filtering is an OPTIONAL feature, advertised in the ServiceProviderConfig with maxResults(Sections 3.4.2.2 and 4). Ten comparison operators exist: eq, ne, co,sw, ew, pr, gt, ge, lt, andle, combined with and, or, not, parentheses, and complex-attribute value paths in square brackets. The evaluator rules around the grammar are normative even where the grammar is not: gt, ge, lt, and leapplied to Boolean or Binary values SHALL fail with invalidFilter; a filter on an attribute of the wrong type evaluates as absent rather than erroring; case sensitivity of string comparisons follows the target attribute's caseExact; and a server MUST decline an unrecognized operator with 400 invalidFilter rather than guessing.

FILTER    = attrExp / logExp / valuePath / *1"not" "(" FILTER ")"

valuePath = attrPath "[" valFilter "]"
            ; FILTER uses sub-attributes of a parent attrPath

valFilter = attrExp / logExp / *1"not" "(" valFilter ")"

attrExp   = (attrPath SP "pr") /
            (attrPath SP compareOp SP compValue)

logExp    = FILTER SP ("and" / "or") SP FILTER

compValue = false / null / true / number / string
            ; rules from JSON (RFC 7159)

compareOp = "eq" / "ne" / "co" /
                   "sw" / "ew" /
                   "gt" / "lt" /
                   "ge" / "le"

attrPath  = [URI ":"] ATTRNAME *1subAttr
            ; SCIM attribute name
            ; URI is SCIM "schema" URI

ATTRNAME  = ALPHA *(nameChar)

nameChar  = "-" / "_" / DIGIT / ALPHA

subAttr   = "." ATTRNAME
            ; a sub-attribute of a complex attribute

Figure 1 of RFC 7644 Section 3.4.2.2, transcribed verbatim (rfc-editor.org, retrieved 2026-11-01).

The grammar contradicts the RFC's own examples in three recorded places, and none is settled. The*1"not" "(" rule forbids the space between not and the parenthesis that the RFC's example filter uses; reported erratum7319 (2023-01-25) proposes*1("not" SP) and remains open. The value-path branch lacks a recursivevalLogExp, so parenthesized value filters of the form the RFC itself demonstrates do not parse; reported erratum 7322corrects it via the held 4690. The evaluation order statement (grouping, then and/or, then attribute operators) reads with not binding looser than attribute operators, which held erratum 4670 disputes the other way. The filter playground implements one consistent reading and flags these three as open questions rather than resolving them silently.

05 · PATCH and bulk

PATCH (Section 3.5.2) is an OPTIONAL feature carried in a PatchOp document,urn:ietf:params:scim:api:messages:2.0:PatchOp: an Operations array ofadd, remove, and replace entries, each with an optionalpath. The path ABNF (Figure 7) extends attribute paths with value-path filters such asmembers[value eq "2819c223..."]. The per-op mutability matrix is where servers earn their conformance: remove on a read-only attribute fails with mutability; an immutable attribute re-asserted with its current value succeeds while a different value is rejected; andnull/[] clear values under the Section 2.5 equivalence. A PATCH that changes nothing still succeeds, with 204 and no body.

The published PATCH material needed repair: verified erratum8096 (verified 2025-10-28) adds the closing brace a Section 3.5.2.1 add example was missing, and reported erratum5295 flags the "already a member, no change" example for returning 204 with an Authorization header and a Location header, neither of which belongs on a 204. The PATCH builder uses that example as a spot-the-invalid-response exercise.

Bulk (Section 3.7) posts a BulkRequest to /Bulk with failOnErrors and anOperations array whose entries carry method, path, bulkId, and data.bulkId values are temporary identifiers for forward references (create the group, then add members to it in the same request); the identifier never appears in any resource id. The server advertises its ceiling as maxOperations in the ServiceProviderConfig and MUST answer 413 (Payload Too Large) when either limit is exceeded, naming the exceeded limit in the error body (Section 3.7.4). Each operation returns its own status, and the response example needed three fixes of its own: verified erratum7916 (verified 2024-05-11) removes a stray "status": "201" line, adds the missing leading brace, and adds a missing comma after"scimType":"invalidSyntax" in the Section 3.7.3 figure. RFC 9967 later defines asynchronous bulk, where each operation's completion arrives as its own event; see thenew-RFCs page.

06 · Errors: the two tables

Section 3.12 defines the error document,urn:ietf:params:scim:api:messages:2.0:Error, with three members: status (the HTTP status as a JSON string, REQUIRED), scimType (a detail keyword, OPTIONAL), anddetail (a human-readable message, OPTIONAL). Table 8 maps status codes to usage, and two rows do the heavy lifting in integration debugging: 409 covers both version conflicts and duplicate resources, and 412 means the resource changed under the client and the request needs a fresh read before retry. Table 9 then defines the detail keywords, opening with the sentence "For HTTP status code 400 (Bad Request) responses, the following detail error types are defined" and listing ten.

scimTypeDescription (condensed)Applicability
invalidFilterthe filter syntax was invalid (does not comply with Figure 1), or the attribute and comparison combination is not supportedGET (3.4.2), POST Search (3.4.3), PATCH path filter (3.5.2)
tooManythe filter yields many more results than the server is willing to calculate or processGET (3.4.2), POST Search (3.4.3)
uniquenessone or more of the attribute values are already in use or are reservedPOST Create (3.3), PUT (3.5.1), PATCH (3.5.2)
mutabilitythe attempted modification is not compatible with the target attribute's mutability or current statePUT (3.5.1), PATCH (3.5.2)
invalidSyntaxthe request body message structure was invalid or did not conform to the request schemaPOST Search (3.4.3), Create (3.3), Bulk (3.7), PUT (3.5.1)
invalidPaththe "path" attribute was invalid or malformed (see Figure 7)PATCH (3.5.2)
noTargetthe specified "path" did not yield an attribute or value that could be operated onPATCH (3.5.2)
invalidValuea required value was missing, or the value was not compatible with the operation or attribute typeGET (3.4.2), POST Create (3.3), Query (3.4.3), PUT (3.5.1), PATCH (3.5.2)
invalidVersthe specified SCIM protocol version is not supported (see Section 3.13)GET (3.4.2), POST (ALL), PUT (3.5.1), PATCH (3.5.2), DELETE (3.6)
sensitivethe request cannot be completed because it carries sensitive (e.g., personal) information in a request URIGET (3.4.2)

Table 9 of RFC 7644 Section 3.12, condensed from the primary text (rfc-editor.org, retrieved 2026-11-01).

Two readings keep the table honest. The 409 uniqueness assignment comes from Section 3.3 and Table 8's conflict row, not from the table's own opening line. The sensitive row is demonstrated in Section 7.5.2 on a 403, not a 400. The error example in Section 3.12 itself shipped invalid: verified erratum 7898(reported and verified 2024-04-17) adds the missing comma after "scimType":"mutability" in the PUT error figure. The error decoder maps real status plus scimType pairs to this section's semantics.

07 · Security on the wire

Section 7 fixes no SCIM-specific authentication scheme: the server advertises what it accepts via WWW-Authenticate, bearer tokens get the usual hygiene guidance, and the server MUST map the authenticated client to an access-control policy. The rule with the longest operational shadow is Section 7.5.2: personal data SHALL NOT be transmitted in request URIs, because URLs are logged end to end. A filter with an email in the query string violates it; the compliant shape is POST Search, which moves the filter into the body. The section's own example figure mislabeled its status as 404 under a 403 HTTP line until verified erratum 6893 corrected the body to match (verified 2022-03-25). The security guidecarries the 2026 additions to this baseline.

08 · References

Normative - the documents the protocol builds on:

Informative - errata, registry, and tooling: