RFC 7644
System for Cross-domain Identity Management: Protocol
RFC 7644: System for Cross-domain Identity Management: Protocol π
Okay bestie, so this is RFC 7644 π, a Standards Track document from the IETF, dated September 2015 (ISSN 2070-1721). P. Hunt, Ed. from Oracle is the editor who led the write-up, with K. Grizzle from SailPoint, M. Ansari from Cisco, E. Wahlstroem from Nexus Technology, and C. Mortimore from Salesforce π«Ά. The title block doesn't list anything it obsoletes or updates, so this one is standing on its own π¦.
Abstract
SCIM (System for Cross-domain Identity Management) is an HTTP-based protocol that makes managing identities across multiple domains way easier through one standardized service π . It's built for stuff like enterprise-to-cloud service providers and inter-cloud setups, and that's not even the full list π. The suite builds on experience with existing schemas and deployments, with a big focus on simple development and integration, while still using existing authentication, authorization, and privacy models π₯. The goal is to cut the cost and complexity of user management by giving you a common user schema, an extension model, and the service protocol defined in this document β¨.
Status of This Memo
This is an Internet Standards Track document. β¨
This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). More info on Internet Standards is in Section 2 of RFC 5741 π.
Info about the current status of this document, any errata, and how to give feedback on it can be found at http://www.rfc-editor.org/info/rfc7644 π¦.
Copyright Notice
Copyright (c) 2015 IETF Trust and the persons identified as the document authors. All rights reserved. π
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication. Please review these documents carefully, since they describe your rights and restrictions for this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty as described in the Simplified BSD License π«Ά.
Table of Contents
1. Introduction and Overview .......................................3
1.1. Intended Audience ..........................................3
1.2. Notational Conventions .....................................4
1.3. Definitions ................................................4
2. Authentication and Authorization ................................5
2.1. Use of Tokens as Authorizations ............................7
2.2. Anonymous Requests .........................................7
3. SCIM Protocol ...................................................8
3.1. Background .................................................8
3.2. SCIM Endpoints and HTTP Methods ............................9
3.3. Creating Resources ........................................11
3.3.1. Resource Types .....................................13
3.4. Retrieving Resources ......................................13
3.4.1. Retrieving a Known Resource ........................14
3.4.2. Query Resources ....................................15
3.4.3. Querying Resources Using HTTP POST .................27
3.5. Modifying Resources .......................................29
3.5.1. Replacing with PUT .................................30
3.5.2. Modifying with PATCH ...............................32
3.6. Deleting Resources ........................................48
3.7. Bulk Operations ...........................................49
3.7.1. Circular Reference Processing ......................51
3.7.2. "bulkId" Temporary Identifiers .....................53
3.7.3. Response and Error Handling ........................58
3.7.4. Maximum Operations .................................63
3.8. Data Input/Output Formats .................................64
3.9. Additional Operation Response Parameters ..................64
3.10. Attribute Notation .......................................66
3.11. "/Me" Authenticated Subject Alias ........................66
3.12. HTTP Status and Error Response Handling ..................67
3.13. SCIM Protocol Versioning .................................71
3.14. Versioning Resources .....................................71
4. Service Provider Configuration Endpoints .......................73
5. Preparation and Comparison of Internationalized Strings ........76
6. Multi-Tenancy ..................................................76
6.1. Associating Clients to Tenants ............................77
6.2. SCIM Identifiers with Multiple Tenants ....................78
7. Security Considerations ........................................78
7.1. HTTP Considerations .......................................78
7.2. TLS Support Considerations ................................78
7.3. Authorization Token Considerations ........................78
7.4. Bearer Token and Cookie Considerations ....................79
7.5. Privacy Considerations ....................................79
7.5.1. Personal Information ...............................79
7.5.2. Disclosure of Sensitive Information in URIs ........80
7.6. Anonymous Requests ........................................80
7.7. Secure Storage and Handling of Sensitive Data .............81
7.8. Case-Insensitive Comparison and International Languages ...82
8. IANA Considerations ............................................82
8.1. Media Type Registration ...................................82
8.2. Registering URIs for SCIM Messages ........................84
9. References .....................................................85
9.1. Normative References ......................................85
9.2. Informative References ....................================================================
Acknowledgements ..................................................88
Contributors ......................................................88
Authors' Addresses ................................................89
1. Introduction and Overview β¨
The SCIM protocol is an application-level, HTTP-based protocol for provisioning and managing identity data on the web and in cross-domain environments, like enterprise-to-cloud service providers or inter-cloud scenarios πΈ. It handles creating, modifying, retrieving, and discovering core identity resources such as Users and Groups, plus custom resources and resource extensions π .
The resources, attributes, and overall schema are defined in the SCIM Core Schema document [RFC7643] π.
1.1. Intended Audience
This document is a guide to SCIM protocol usage for two crowds: SCIM HTTP service providers, and HTTP clients who provision information to those providers or retrieve information from them π«Ά.
1.2. Notational Conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119]. These key words are capitalized when they unambiguously specify requirements of the protocol or application features and behavior that affect the interoperability and security of implementations. When these words are not capitalized, they carry their natural-language meaning π§ .
For readability, examples are not URL encoded. Implementers MUST percent-encode URLs as described in Section 2.1 of [RFC3986] π.
Throughout this document, figures may contain spaces and extra line wrapping to improve readability and fit space limitations. Similarly, some URIs inside examples have been shortened for space and readability (as indicated by "...") β¨.
1.3. Definitions
This specification uses the definitions from [RFC7643] and defines the following additional term:
Base URI
The SCIM HTTP protocol is described in terms of a path relative to a Base URI. The Base URI MUST NOT contain a query string, because clients MAY append additional path information and query parameters when forming the request. The base URI is a URL that most often consists of the "https" protocol scheme, a domain name, and some initial path [RFC3986]. For example:
"https://example.com/scim/"
For readability, all examples in this document assume that the SCIM service root and the server root are the same (no path prefix). SCIM servers may be deployed using any URI path prefix. For example, a SCIM server might have a prefix of:
"https://example.com/"
"https://example.com/scim/tenancypath/"
Additionally, a client MAY apply a version number to the server root prefix (see Section 3.13) π.
2. Authentication and Authorization β¨
Okay bestie, so SCIM is built on HTTP and doesn't come with its own special auth scheme π . Instead it leans on TLS and/or the standard HTTP authentication and authorization schemes from [RFC7235]. Here are some of the methods people could use, among others π¦:
- TLS Client Authentication: The SCIM service provider MAY ask for TLS client authentication, which is also called mutual authentication π. Check out Section 7.3 of [RFC5246].
- HOBA Authentication: HTTP Origin-Bound Authentication (HOBA) is a twist on TLS client authentication. It uses a digital-signature design for an HTTP authentication method (see [RFC7486]). It can also work in JavaScript-based authentication embedded in HTML. HOBA is an alternative to HTTP schemes that need passwords, so it skips all the password drama, like leaked server-side password databases π.
- Bearer Tokens: Bearer tokens [RFC6750] MAY be used when they're combined with TLS and a token framework like OAuth 2.0 [RFC6749]. Tokens issued on weak or no authentication of the authorizing users and/or OAuth clients SHOULD NOT be used, unless they're something like single-use tokens for one-time requests, such as anonymous registration (see Section 3.3). For the security considerations around bearer tokens in SCIM, see Section 7.4. Bearer tokens usually represent an authorization, and it's assumed that the authorization came from a successful authentication of the SCIM client. So the SCIM service provider must have a way to validate, parse, and/or "introspecting" the bearer token to get the relevant authentication and authorization info. How that works is assumed to be defined by the token-issuing system and is beyond the scope of this spec π§.
- PoP Tokens: A proof-of-possession (PoP) token shows that whoever presents it has a particular key, and the recipient can cryptographically confirm that. This is sometimes described as the presenter being a holder of the key π. See [OAuth-PoP-Arch] for an example of one and how it gets used.
- Cookies: JavaScript clients MAY assert HTTP cookies over TLS that carry an authentication state the SCIM service provider understands (see [RFC6265]). For example, web-form authentication already happened with the user and cookies were set to represent that auth state πͺ. For SCIM purposes, the security considerations in Section 7.4 apply.
- Basic Authentication: Basic authentication should be avoided, since it's a single factor built on a fairly static, symmetric secret π¬. Implementers SHOULD combine basic authentication with other factors. The security considerations of HTTP Basic are well documented in [HTTP-BASIC-AUTH], so implementers are encouraged to use stronger authentication methods. Picking specific authentication and authorization methods is out of scope for SCIM, but this info is here as a resource for implementers.
As per Section 4.1 of [RFC7235], a SCIM service provider SHALL indicate its supported HTTP authentication schemes via the WWW-Authenticate header π£.
Regardless of methodology, the SCIM service provider MUST be able to map the authenticated client to an access control policy, so it can figure out whether that client is allowed to retrieve and update SCIM resources. For example, a browser session might have been set up through an HTTP cookie or TLS client authentication, but the unique client MUST be mapped to a security subject (e.g., User). The authorization model and how this mapping happens are beyond the scope of this specification π.
When processing requests, the service provider SHOULD consider the subject making the request, and whether the action makes sense for that subject and the resource being affected. The subject is usually figured out directly or indirectly from the Authorization header in the request π. For example, a subject MAY be permitted to retrieve and update their own User resource, but they'll normally have restricted access to resources tied to other Users. Sometimes the SCIM service provider might only grant access to a subject's own associated User resource, like when someone is updating their personal contact attributes.
For illustrative purposes only, the SCIM protocol examples show an OAuth 2.0 bearer token value [RFC6750] in the authorization header, like this:
GET /Users/2819c223-7f76-453a-919d-413861904646 HTTP/1.1
Host: example.com
Authorization: Bearer h480djs93hd8
This is not meant to imply that bearer tokens are preferred. The bearer tokens in the spec just reflect common implementation practice πΈ.
2.1. Use of Tokens as Authorizations
When using bearer tokens or PoP tokens that represent an authorization grant, like a grant issued by OAuth (see [RFC6749]), implementers SHOULD consider the type of authorization granted, any authorized scopes (see Section 3.3 of [RFC6749]), and the security subject(s) that SHOULD be mapped from the authorization when they're thinking about local access control rules π§ . Section 6 of [RFC7521] lays out common authorization scenarios, including:
- A client using an assertion to authenticate and/or act on behalf of itself,
- A client acting on behalf of a user, and
- A client acting on behalf of an anonymous user (for example, see Section 2.2).
When using OAuth authorization tokens, implementers MUST take into account the threats and countermeasures related to the use of client authorizations, as documented in Section 8 of [RFC7521] π¨. When using other token formats or frameworks, implementers MUST take into account similar threats and countermeasures, especially the ones documented by the relevant specifications.
2.2. Anonymous Requests
In some SCIM deployments, it MAY be okay to allow unauthenticated (anonymous) requests π«Ά. One example is a user self-registration request, where the service provider decides to accept a SCIM Create request (see Section 3.3) from an anonymous client. See Section 7.6 for the security considerations around anonymous requests.
3. SCIM Protocol
3.1. Background
SCIM is a protocol built on HTTP [RFC7230] β¨. Along with HTTP headers and URIs, SCIM uses JSON [RFC7159] payloads to carry SCIM resources, plus protocol-specific payload messages that convey request parameters and response info, like errors. Both resources and messages get passed as JSON-based structures in the message body of an HTTP request or response. To identify this content, SCIM uses the media type application/scim+json (see Section 8.1) π.
A SCIM "resource" is a JSON object [RFC7159] that can be created, maintained, and retrieved through the HTTP request methods described in this document. Each JSON resource representation contains a schemas attribute, which holds a list of one or more URIs pointing to the included SCIM schemas. Those schemas tell you which attributes are in the resource π. Specific info about which attributes a schema defines MAY be obtained by querying a SCIM service provider's /Schemas endpoint for a schema definition (see Section 8.7 of [RFC7643]). Responses from that endpoint describe the schema the service provider supports, including attribute characteristics like cardinality, case-exactness, mutability, uniqueness, returnability, and whether attributes are required. SCIM schemas and an associated extension model are defined in [RFC7643], but SCIM clients should expect that some attribute schemas may change from one service provider to another, especially across administrative domains π. When SCIM is used as an open protocol in front of an application service, it's pretty reasonable to expect that some service providers only support a subset of the schema defined in [RFC7643].
A SCIM message conveys protocol parameters related to a SCIM request or response, and this specification defines those parameters π¨. Just like a SCIM resource, a SCIM message is a JSON object [RFC7159] that contains a schemas attribute with a URI whose namespace prefix MUST begin with urn:ietf:params:scim:api:. Since SCIM protocol messages are fixed and defined by SCIM specifications and registered extensions, SCIM message schemas using that prefix URN SHALL NOT be discoverable through the /Schemas endpoint π
ββοΈ.
SCIM is meant for cross-domain scenarios where schemas and implementations can vary, so techniques like document validation (e.g., [XML-Schema]) are not recommended π
. A SCIM service provider interprets a request in the context of its own schema (which may differ from the client's schema), and it follows the defined processing rules for each request. The sections that follow define those processing rules and make allowances for schema differences where they make sense. For example, in a SCIM PUT request, readOnly attributes are ignored while readWrite attributes get updated. A SCIM client doesn't need to figure out which attributes are readOnly, and it doesn't have to remove them from a PUT request for it to be accepted π―. Similarly, a SCIM client SHOULD NOT expect a service provider to return SCIM resources with exactly the same schema and values as the ones submitted. SCIM responses SHALL reflect the resource state as interpreted by the SCIM service provider π¦
3.2. SCIM Endpoints and HTTP Methods β¨
okay so SCIM has a set of well-known endpoints and HTTP methods for managing the resources defined in the SCIM Core Schema document ([RFC7643]) π. "User" lives at /Users and "Group" lives at /Groups, easy peasy. Service providers that support extended resources SHOULD name their endpoints by pluralizing the resource name from the extended schema, which just means adding an 's' π
. But pluralization can be messy, bestie. A resource called "Person" could be "Persons" or "People" π, so clients SHOULD find the endpoints through the /ResourceTypes endpoint instead of guessing. Lowkey the safest move.
Here's what each HTTP method is for π¦:
HTTP SCIM Usage
Method
------ --------------------------------------------------------------
GET Retrieves one or more complete or partial resources.
POST Depending on the endpoint, creates new resources, creates a
search request, or MAY be used to bulk-modify resources.
PUT Modifies a resource by replacing existing attributes with a
specified set of replacement attributes (replace). PUT
MUST NOT be used to create new resources.
PATCH Modifies a resource with a set of client-specified changes
(partial update).
DELETE Deletes a resource.
Table 1: SCIM HTTP Methods
PUT MUST NOT be used to create new resources, so don't even try it π ββοΈ. POST is the multitasker here: it can create, search, or MAY be used to bulk-modify stuff depending on the endpoint π.
And here are the endpoints themselves, all mapped out πΈ:
Resource Endpoint Operations Description
-------- ---------------- ---------------------- --------------------
User /Users GET (Section 3.4.1), Retrieve, add,
POST (Section 3.3), modify Users.
PUT (Section 3.5.1),
PATCH (Section 3.5.2),
DELETE (Section 3.6)
Group /Groups GET (Section 3.4.1), Retrieve, add,
POST (Section 3.3), modify Groups.
PUT (Section 3.5.1),
PATCH (Section 3.5.2),
DELETE (Section 3.6)
Self /Me GET, POST, PUT, PATCH, Alias for operations
DELETE (Section 3.11) against a resource
mapped to an
authenticated
subject (e.g.,
User).
Service /ServiceProvider GET (Section 4) Retrieve service
provider Config provider's
config. configuration.
Resource /ResourceTypes GET (Section 4) Retrieve supported
type resource types.
Schema /Schemas GET (Section 4) Retrieve one or more
supported schemas.
Bulk /Bulk POST (Section 3.7) Bulk updates to one
or more resources.
Search [prefix]/.search POST (Section 3.4.3) Search from system
root or within a
resource endpoint
for one or more
resource types using
POST.
Table 2: Defined Endpoints
Every request to the service provider goes over HTTP methods, following Section 4.3 of [RFC7231], and it all happens on a URL built from the Base URL π. Responses come back in the HTTP response body as JSON. For errors, the status code SHOULD be sent in the HTTP status code of the response (when that's possible), and it SHOULD also show up in the response body too (see Section 3.12) π¨.
3.3. Creating Resources
wanna make something new? Send an HTTP POST to the resource endpoint, like /Users or /Groups π§. The endpoint discovery stuff (Section 4) tells you which one to use.
The server SHALL process attributes according to these mutability rules π:
- In the request body, attributes whose mutability is "readOnly" (see Sections 2.2 and 7 of [RFC7643]) SHALL be ignored.
- Attributes whose mutability is "readWrite" (see Section 2.2 of [RFC7643]) and that are omitted from the request body MAY be assumed to be not asserted by the client. The service provider MAY assign a default value to non-asserted attributes in the final resource representation.
- Service providers MAY take into account whether or not a client has access to all of the resource's attributes when deciding whether or not non-asserted attributes should be defaulted.
- Clients that intend to override existing or server-defaulted values for attributes MAY specify "null" for a single-valued attribute or an empty array "[]" for a multi-valued attribute to clear all values.
When the service provider successfully creates the new resource, an HTTP response SHALL be returned with HTTP status code 201 (Created) β¨. The response body SHOULD contain the service provider's representation of the newly created resource. The URI of the created resource SHALL include, in the HTTP "Location" header and the HTTP body, a JSON representation [RFC7159] with the attribute "meta.location". The server is totally free to change or ignore whatever you POSTed, so getting the full representation back is super useful, since it lets the client match up its view of the new resource with the server's view π«Ά.
If creating the requested resource clashes with existing resources (say, a "User" with a duplicate "userName"), the service provider MUST return HTTP status code 409 (Conflict) with a "scimType" error code of "uniqueness", as per Section 3.12 π.
Here's an example. A client sends a POST with a "User" to the "/Users" endpoint π:
POST /Users HTTP/1.1
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"bjensen",
"externalId":"bjensen",
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara"
}
}
The server replies with an HTTP status code 201 (Created) to say the creation worked, and it sends back a copy of the resource it made π¦:
HTTP/1.1 201 Created
Content-Type: application/scim+json
Location:
https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646
ETag: W/"e180ee84f0671b1"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"externalId":"bjensen",
"meta":{
"resourceType":"User",
"created":"2011-08-01T21:32:44.882Z",
"lastModified":"2011-08-01T21:32:44.882Z",
"location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
"version":"W\/\"e180ee84f0671b1\""
},
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara"
},
"userName":"bjensen"
}
3.3.1. Resource Types
When you add a resource to a specific endpoint, the meta attribute "resourceType" SHALL be set by the HTTP service provider to the matching resource type for that endpoint πΈ. So a POST to "/Users" sets "resourceType" to "User", and "/Groups" sets it to "Group". Simple as that, babe π.
3.4. Retrieving Resources
Resources MAY be retrieved through opaque, unique URLs or through queries (see Section 3.4.2) π. The attributes you get back are defined in the server's attribute schema (see Section 8.7 of [RFC7643]), and request parameters (see Section 3.9) can change them. By default, the attributes in a response are the ones whose "returned" setting is "always" or "default" (see Section 2.2 of [RFC7643]) β¨.
3.4.1. Retrieving a Known Resource
To grab a resource you already know about, send GET requests to the resource endpoint, like "/Users/{id}", "/Groups/{id}", or "/Schemas/{id}", where "{id}" is the resource identifier (for example, the value of the "id" attribute) π§.
If the resource exists, the server responds with HTTP status code 200 (OK) and puts the result in the response body π.
This example pulls up a single User through the "/Users" endpoint π :
GET /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
The server responds with:
HTTP/1.1 200 OK
Content-Type: application/scim+json
Location:
https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646
ETag: W/"f250dd84f0671c3"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"externalId":"bjensen",
"meta":{
"resourceType":"User",
"created":"2011-08-01T18:29:49.793Z",
"lastModified":"2011-08-01T18:29:49.793Z",
"location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
"version":"W\/\"f250dd84f0671c3\""
},
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara"
},
"userName":"bjensen",
"phoneNumbers":[
{
"value":"555-555-8377",
"type":"work"
}
],
"emails":[
{
"value":"bjensen@example.com",
"type":"work"
}
]
}
3.4.2. Query Resources β¨
okay bestie, SCIM has a standard set of query parameters that let you filter, sort, and paginate so you get back zero or more resources in a query response π
. Queries MAY be made against a single resource, a resource type endpoint (like "/Users"), or the service provider Base URI π¦. SCIM service providers MAY support extra query parameters that aren't listed here, and they SHOULD ignore any query parameter they don't recognize instead of rejecting the whole query. That's for versioning compatibility, so nobody's request explodes when things change π.
Responses MUST be identified with this URI: "urn:ietf:params:scim:api:messages:2.0:ListResponse" π. These attributes are defined for responses:
"totalResults": the total number of results returned by the list or query operation. The value can be bigger than the number of resources returned, like when you only get a single page of results and more pages exist (see Section 3.4.2.4) π. REQUIRED."Resources": a multi-valued list of complex objects holding the requested resources. This MAY be a subset of the full set if pagination (Section 3.4.2.4) was requested πΈ. REQUIRED if"totalResults"is non-zero."startIndex": the 1-based index of the first result in the current set of list results β¨. REQUIRED when partial results come back because of pagination."itemsPerPage": the number of resources returned in one list response page π§. REQUIRED when partial results come back because of pagination.
A query with zero matches SHALL still return success (HTTP status code 200), with "totalResults" set to 0. It's giving "nothing found, but still a success" π.
Here's an example query that asks for the userName of every User π:
GET /Users?attributes=userName
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
And here's the response to that query π:
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults":2,
"Resources":[
{
"id":"2819c223-7f76-453a-919d-413861904646",
"userName":"bjensen"
},
{
"id":"c75ad752-64ae-4823-840d-ffa80929976c",
"userName":"jsmith"
}
]
}
Notice that "id" shows up even though we only asked for userName. That's because the "id" attribute has the "returned" characteristic set to "always" π«Ά.
3.4.2.1. Query Endpoints π
Queries MAY be performed against a SCIM resource object, a resource type endpoint, or a SCIM server root. For example:
"/Users/{id}"
"/Users"
"/Groups"
A query against a server root means all resources within the server SHALL be included, subject to filtering π. A filter expression using "meta.resourceType" MAY be used to limit results to one or more specific resource types, which lets you leave the others out π¦. For example:
filter=(meta.resourceType eq User) or (meta.resourceType eq Group)
Now the important bit π. If a SCIM service provider decides too many results would come back (for example, because a client queried a resource type endpoint or the server base URI), the server SHALL reject the request. It does that by returning an HTTP response with HTTP status code 400 (Bad Request) and the JSON attribute "scimType" set to "tooMany" (see Table 9) π.
When a query goes through endpoints that include more than one SCIM resource type (like a query from the server root endpoint), filters MUST be processed as outlined in Section 3.4.2.2 β¨. For filtered attributes that don't belong to a particular resource type, the service provider SHALL treat the attribute as if there is no attribute value. So a presence or equality filter on an undefined attribute evaluates to false π.
3.4.2.2. Filtering π
Filtering is an OPTIONAL parameter for SCIM service providers πΈ. Clients MAY find out what filter capabilities a provider has by looking at the "filter" attribute of the "ServiceProviderConfig" endpoint (see Section 4) π. Clients MAY ask for a subset of resources by putting a filter expression in the "filter" query parameter π. When that's specified, only the resources matching the filter expression SHALL be returned. The expression language used with the filter parameter supports references to attributes and literals π§.
Attribute names and attribute operators in filters are case insensitive. The two expressions below evaluate to the same logical value, so both work π:
filter=userName Eq "john"
filter=Username eq "john"
The filter parameter MUST contain at least one valid expression (see Table 3). Each expression MUST contain an attribute name, followed by an attribute operator and an optional value. Multiple expressions MAY be combined using logical operators (see Table 4) π¦. Expressions MAY be grouped together using round brackets "(" and ")" (see Table 5) π.
The operators you can use in an expression are listed in Table 3 π:
+----------+-------------+------------------------------------------+
| Operator | Description | Behavior |
+----------+-------------+------------------------------------------+
| eq | equal | The attribute and operator values must |
| | | be identical for a match. |
| | | |
| ne | not equal | The attribute and operator values are |
| | | not identical. |
| | | |
| co | contains | The entire operator value must be a |
| | | substring of the attribute value for a |
| | | match. |
| | | |
| sw | starts with | The entire operator value must be a |
| | | substring of the attribute value, |
| | | starting at the beginning of the |
| | | attribute value. This criterion is |
| | | satisfied if the two strings are |
| | | identical. |
| | | |
| ew | ends with | The entire operator value must be a |
| | | substring of the attribute value, |
| | | matching at the end of the attribute |
| | | value. This criterion is satisfied if |
| | | the two strings are identical. |
| | | |
| pr | present | If the attribute has a non-empty or |
| | (has value) | non-null value, or if it contains a |
| | | non-empty node for complex attributes, |
| | | there is a match. |
| | | |
| gt | greater | If the attribute value is greater than |
| | than | the operator value, there is a match. |
| | | The actual comparison is dependent on |
| | | the attribute type. For string |
| | | attribute types, this is a |
| | | lexicographical comparison, and for |
| | | DateTime types, it is a chronological |
| | | comparison. For integer attributes, it |
| | | is a comparison by numeric value. |
| | | Boolean and Binary attributes SHALL |
| | | cause a failed response (HTTP status |
| | | code 400) with "scimType" of |
| | | "invalidFilter". |
| | | |
| ge | greater | If the attribute value is greater than |
| | than or | or equal to the operator value, there is |
| | equal to | a match. The actual comparison is |
| | | dependent on the attribute type. For |
| | | string attribute types, this is a |
| | | lexicographical comparison, and for |
| | | DateTime types, it is a chronological |
| | | comparison. For integer attributes, it |
| | | is a comparison by numeric value. |
| | | Boolean and Binary attributes SHALL |
| | | cause a failed response (HTTP status |
| | | code 400) with "scimType" of |
| | | "invalidFilter". |
| | | |
| lt | less than | If the attribute value is less than the |
| | | operator value, there is a match. The |
| | | actual comparison is dependent on the |
| | | attribute type. For string attribute |
| | | types, this is a lexicographical |
| | | comparison, and for DateTime types, it |
| | | is a chronological comparison. For |
| | | integer attributes, it is a comparison |
| | | by numeric value. Boolean and Binary |
| | | attributes SHALL cause a failed response |
| | | (HTTP status code 400) with "scimType" |
| | | of "invalidFilter". |
| | | |
| le | less than | If the attribute value is less than or |
| | or equal to | equal to the operator value, there is a |
| | | match. The actual comparison is |
| | | dependent on the attribute type. For |
| | | string attribute types, this is a |
| | | lexicographical comparison, and for |
| | | DateTime types, it is a chronological |
| | | comparison. For integer attributes, it |
| | | is a comparison by numeric value. |
| | | Boolean and Binary attributes SHALL |
| | | cause a failed response (HTTP status |
| | | code 400) with "scimType" of |
| | | "invalidFilter". |
+----------+-------------+------------------------------------------+
Table 3: Attribute Operators π
okay so the logical operators are the glue that lets you combine conditions, and they're giving clarity πβ¨
+----------+-------------+------------------------------------------+
| Operator | Description | Behavior |
+----------+-------------+------------------------------------------+
| and | Logical | The filter is only a match if both |
| | "and" | expressions evaluate to true. |
| | | |
| or | Logical | The filter is a match if either |
| | "or" | expression evaluates to true. |
| | | |
| not | "Not" | The filter is a match if the expression |
| | function | evaluates to false. |
+----------+-------------+------------------------------------------+
Table 4: Logical Operators
Next up is the grouping table, where the parentheses and square brackets come in π
+----------+-------------+------------------------------------------+
| Operator | Description | Behavior |
+----------+-------------+------------------------------------------+
| ( ) | Precedence | Boolean expressions MAY be grouped using |
| | grouping | parentheses to change the standard order |
| | | of operations, i.e., to evaluate logical |
| | | "or" operators before logical "and" |
| | | operators. |
| | | |
| [ ] | Complex | Service providers MAY support complex |
| | attribute | filters where expressions MUST be |
| | filter | applied to the same value of a parent |
| | grouping | attribute specified immediately before |
| | | the left square bracket ("["). The |
| | | expression within square brackets ("[" |
| | | and "]") MUST be a valid filter |
| | | expression based upon sub-attributes of |
| | | the parent attribute. Nested |
| | | expressions MAY be used. See examples |
| | | below. |
+----------+-------------+------------------------------------------+
Table 5: Grouping Operators
Now the grammar bit. It's serious, but it's also very neat π§ SCIM filters MUST conform to the following ABNF [RFC5234] rules:
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: ABNF Specification of SCIM Filters
In the above ABNF rules, the "compValue" (comparison value) rule is built on JSON Data Interchange format ABNF rules as specified in [RFC7159], "DIGIT" and "ALPHA" are defined per Appendix B.1 of [RFC5234], and "URI" is defined per Appendix A of [RFC3986].
Filters MUST be evaluated in this order of operations, from highest precedence to lowest π
- Grouping operators
- Logical operators - where "not" takes precedence over "and", which takes precedence over "or"
- Attribute operators
If the specified attribute in a filter expression is a multi-valued attribute, the filter matches if any of the values of the specified attribute match the specified criterion. So if a User has multiple "emails" values, only one has to match for the entire User to match, which is such a main character move π For complex attributes, a fully qualified sub-attribute MUST be specified using standard attribute notation (Section 3.10). For example, to filter by userName, the parameter value is "userName". To filter by first name, the parameter value is "name.givenName".
When applying a comparison (e.g., "eq") or presence filter (e.g., "pr") to a defaulted attribute, the service provider SHALL use the value that was returned to the client that last created or modified the attribute. Very important, bestie π«Ά
Providers MAY support additional filter operations if they choose. Providers MUST decline to filter results if the specified filter operation is not recognized, and they return an HTTP 400 error with a "scimType" error of "invalidFilter" and an appropriate human-readable response as per Section 3.12. For example, if a client specified an unsupported operator named 'regex', the service provider should specify an error response description identifying the client error, e.g., 'The operator 'regex' is not supported.' π
When comparing attributes of type String, the case sensitivity for String type attributes SHALL be determined by the attribute's "caseExact" characteristic (see Section 2.2 of [RFC7643]).
Clients MAY query by schema or schema extensions by using a filter expression including the "schemas" attribute (as shown in Figure 2). π
The following are examples of valid filters. Some attributes (e.g., rooms and rooms.number) are hypothetical extensions and are not part of the SCIM core schema, so don't copy them blindly π
filter=userName eq "bjensen"
filter=name.familyName co "O'Malley"
filter=userName sw "J"
filter=urn:ietf:params:scim:schemas:core:2.0:User:userName sw "J"
filter=title pr
filter=meta.lastModified gt "2011-05-13T04:42:34Z"
filter=meta.lastModified ge "2011-05-13T04:42:34Z"
filter=meta.lastModified lt "2011-05-13T04:42:34Z"
filter=meta.lastModified le "2011-05-13T04:42:34Z"
filter=title pr and userType eq "Employee"
filter=title pr or userType eq "Intern"
filter=
schemas eq "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
filter=userType eq "Employee" and (emails co "example.com" or
emails.value co "example.org")
filter=userType ne "Employee" and not (emails co "example.com" or
emails.value co "example.org")
filter=userType eq "Employee" and (emails.type eq "work")
filter=userType eq "Employee" and emails[type eq "work" and
value co "@example.com"]
filter=emails[type eq "work" and value co "@example.com"] or
ims[type eq "xmpp" and value co "@foo.com"]
Figure 2: Example Filters
3.4.2.3. Sorting β¨
Sort is OPTIONAL, so no pressure π¦ Clients MAY discover sort capability by looking at the "sort" attribute of the service provider configuration (see Section 4). Sorting lets clients choose the order in which resources come back, using a combination of "sortBy" and "sortOrder" URL parameters.
- sortBy: The "sortBy" parameter specifies the attribute whose value SHALL be used to order the returned responses. If the "sortBy" attribute corresponds to a singular attribute, resources are sorted according to that attribute's value. If it's a multi-valued attribute, resources are sorted by the value of the primary attribute (see Section 2.4 of [RFC7643]), if any, or else by the first value in the list, if any. If the attribute is complex, the attribute name must be a path to a sub-attribute in standard attribute notation (Section 3.10), e.g.,
sortBy=name.givenName. For all attribute types, if there is no data for the specified "sortBy" value, those resources are sorted via the "sortOrder" parameter, i.e., they are ordered last if ascending and first if descending. Sneaky, but it makes sense π - sortOrder: The order in which the "sortBy" parameter is applied. Allowed values are "ascending" and "descending". If a value for "sortBy" is provided and no "sortOrder" is specified, "sortOrder" SHALL default to ascending. String type attributes are case insensitive by default, unless the attribute type is defined as a case-exact string. "sortOrder" MUST sort according to the attribute type. That means that for case-insensitive attributes, the result is sorted using case-insensitive Unicode alphabetic sort order with no specific locale implied, and for case-exact attribute types, the result is sorted using case-sensitive Unicode alphabetic sort order. Sorting, but make it precise π
3.4.2.4. Pagination β¨
Okay so pagination is how you "page through" a giant pile of resources without overwhelming the client or the service provider π«Ά. You can combine these parameters to walk through the whole list one chunk at a time. Pagination isn't stateful, though, so clients MUST be prepared to handle inconsistent results π. Like, a request for 10 resources starting at startIndex 1 MAY give you different stuff if you repeat it, because the resources on the service provider can change between requests π. The parameters and general behavior come from the OpenSearch Protocol [OpenSearch] πΈ.
Table 6 is the rundown on the URL pagination parameters π:
+------------+----------------------------+-------------------------+
| Parameter | Description | Default |
+------------+----------------------------+-------------------------+
| startIndex | The 1-based index of the | 1 |
| | first query result. A | |
| | value less than 1 SHALL be | |
| | interpreted as 1. | |
| | | |
| count | Non-negative integer. | None. When specified, |
| | Specifies the desired | the service provider |
| | maximum number of query | MUST NOT return more |
| | results per page, e.g., | results than specified, |
| | 10. A negative value | although it MAY return |
| | SHALL be interpreted as | fewer results. If |
| | "0". A value of "0" | unspecified, the |
| | indicates that no resource | maximum number of |
| | results are to be returned | results is set by the |
| | except for "totalResults". | service provider. |
+------------+----------------------------+-------------------------+
Table 6: Pagination Request Parameters
Table 7 covers the pagination attributes the service provider sends back in the query response π:
+--------------+----------------------------------------------------+
| Element | Description |
+--------------+----------------------------------------------------+
| itemsPerPage | Non-negative integer. Specifies the number of |
| | query results returned in a query response page, |
| | e.g., 10. |
| | |
| totalResults | Non-negative integer. Specifies the total number |
| | of results matching the client query, e.g., 1000. |
| | |
| startIndex | The 1-based index of the first result in the |
| | current set of query results, e.g., 1. |
+--------------+----------------------------------------------------+
Table 7: Pagination Response Elements
Here's an example π§. To grab the first 10 Users, set startIndex to 1 and count to 10:
GET /Users?startIndex=1&count=10
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
The response comes back with paging metadata, similar to this (the actual resources are removed for brevity) π :
{
"totalResults":100,
"itemsPerPage":10,
"startIndex":1,
"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"Resources":[{
...
}]
}
Figure 3: ListResponse Format for Returning Multiple Resources
So to keep paging after that, just set startIndex to 11 and re-fetch, like /Users?startIndex=11&count=10 π. Easy peasy π¦.
3.4.2.5. Attributes π
These attributes control which attributes SHALL be returned with a returned resource π. SCIM clients MAY use one of these two OPTIONAL parameters, and they MUST be supported by SCIM service providers β¨:
attributes: A multi-valued list of strings naming the resource attributes to return in the response. It overrides the set of attributes that would be returned by default. Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters.excludedAttributes: A multi-valued list of strings naming the resource attributes to be removed from the default set of attributes to return. This parameter SHALL have no effect on attributes whose schema "returned" setting is "always" (see Sections 2.2 and 7 of [RFC7643]). Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters.
3.4.3. Querying Resources Using HTTP POST π¦
Clients MAY run queries without putting any parameters on the URL π. Instead they use the HTTP POST verb with the /.search path extension. Tacking /.search onto the end of a valid SCIM endpoint SHALL be used to signal that the HTTP POST verb is meant to be a query operation π.
To create a new query result set, a SCIM client sends an HTTP POST request to the desired SCIM resource endpoint (the one ending in /.search) π«Ά. The body of that POST request MAY include any of the parameters defined in Section 3.4.2.
Query requests MUST be identified using this URI: urn:ietf:params:scim:api:messages:2.0:SearchRequest. These are the attributes defined for query requests:
attributes: A multi-valued list of strings naming the resource attributes to return in the response. It overrides the set of attributes that would be returned by default. Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters. OPTIONAL.excludedAttributes: A multi-valued list of strings naming the resource attributes to be removed from the default set of attributes to return. This parameter SHALL have no effect on attributes whose schema "returned" setting is "always" (see Sections 2.2 and 7 of [RFC7643]). Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters. OPTIONAL.filter: The filter string used to request a subset of resources. The filter string MUST be a valid filter (Section 3.4.2.2) expression. OPTIONAL.sortBy: A string naming the attribute whose value SHALL be used to order the returned responses. ThesortByattribute MUST be in standard attribute notation (Section 3.10) form. See Section 3.4.2.3. OPTIONAL.sortOrder: A string indicating the order in which thesortByparameter is applied. Allowed values are "ascending" and "descending". See Section 3.4.2.3. OPTIONAL.startIndex: An integer indicating the 1-based index of the first query result. See Section 3.4.2.4. OPTIONAL.count: An integer indicating the desired maximum number of query results per page. See Section 3.4.2.4. OPTIONAL.
After an HTTP POST request comes in, a response is returned as specified in Section 3.4.2 β¨.
Here's an HTTP POST Query request with the search parameters "attributes", "filter", and "count" included π:
POST /.search
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:SearchRequest"],
"attributes": ["displayName", "userName"],
"filter":
"displayName sw \"smith\"",
"startIndex": 1,
"count": 10
}
Figure 4: Example POST Query Request
And this is the query response with the first page of results. To keep it short, only two matches are shown: one User and one Group πΈ.
HTTP/1.1 200 OK
Content-Type: application/scim+json
Location: https://example.com/.search
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults":100,
"itemsPerPage":10,
"startIndex":1,
"Resources":[
{
"id":"2819c223-7f76-413861904646",
"userName":"jsmith",
"displayName":"Smith, James"
},
{
"id":"c8596b90-7539-4f20968d1908",
"displayName":"Smith Family"
},
...
]
}
Figure 5: Example POST Query Response
3.5. Modifying Resources π
Resources can be modified in whole or in part, using HTTP PUT or HTTP PATCH respectively π₯. Implementers MUST support HTTP PUT as specified in Section 4.3 of [RFC7231]. Resources such as Groups can be very large, so implementers SHOULD support HTTP PATCH [RFC5789] to enable partial resource modifications π . Whether a service provider supports HTTP PATCH may be discovered by querying the service provider configuration (see Section 4) π¦.
3.5.1. Replacing with PUT β¨
okay so HTTP PUT is the move for replacing a resource's attributes π If a client already grabbed the whole resource, revised it, and is ready to send it back, it MAY replace the resource using an HTTP PUT π«Ά BUT the service provider is the one who assigns SCIM resource identifiers, so HTTP PUT MUST NOT be used to create new resources π ββοΈ no sneaky creating through PUT, periodt.
Since PUT is all about replacing all the attributes, SCIM clients MAY send every attribute, no matter each attribute's mutability π The server then does attribute-by-attribute replacements using these mutability rules:
- readWrite, writeOnly: Any values provided SHALL replace the existing attribute values. π«§
- Attributes whose mutability is
"readWrite"that get left out of the request body MAY be assumed to be not asserted by the client. The service provider MAY assume that any existing values are to be cleared, or the service provider MAY assign a default value to the final resource representation. Service providers MAY take into account whether or not a client has access to, or understands, all of the resource's attributes when deciding whether non-asserted attributes SHALL be removed or defaulted. Clients that want to override a server's defaults MAY specify"null"for a single-valued attribute, or an empty array"[]"for a multi-valued attribute, to clear all values. π§Ή
- Attributes whose mutability is
- immutable: If one or more values are already set for the attribute, the input value(s) MUST match, or HTTP status code 400 SHOULD be returned with a
"scimType"error code of"mutability". If the service provider has no existing values, the new value(s) SHALL be applied. π - readOnly: Any values provided SHALL be ignored. π
If an attribute is "required", clients MUST specify the attribute in the PUT request. no skipping it, bestie π
Unless otherwise specified, a successful PUT operation returns a 200 OK response code and the entire resource within the response body. This lets the client line up its view of the updated resource with the service provider's view π¦ Here's an example request:
PUT /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"userName":"bjensen",
"externalId":"bjensen",
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara",
"middleName":"Jane"
},
"roles":[],
"emails":[
{
"value":"bjensen@example.com"
},
{
"value":"babs@jensen.org"
}
]
}
And the service sends back the whole updated User π
HTTP/1.1 200 OK
Content-Type: application/scim+json
ETag: W/"b431af54f0671a2"
Location:
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"userName":"bjensen",
"externalId":"bjensen",
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara",
"middleName":"Jane"
},
"emails":[
{
"value":"bjensen@example.com"
},
{
"value":"babs@jensen.org"
}
],
"meta": {
"resourceType":"User",
"created":"2011-08-08T04:56:22Z",
"lastModified":"2011-08-08T08:00:12Z",
"location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
"version":"W\/\"b431af54f0671a2\""
}
}
3.5.2. Modifying with PATCH π©Ή
HTTP PATCH is an OPTIONAL server function πΈ It lets clients update one or more attributes of a SCIM resource using a sequence of operations that "add", "remove", or "replace" values. Clients may check whether a service provider supports PATCH by querying the service provider configuration (see Section 4) π
The general shape of a SCIM PATCH request is based on JSON Patch [RFC6902]. The big difference is that SCIM servers do not support array indexing, and they don't support the [RFC6902] operation types for messing with array elements, like "move" π ββοΈ
The body of each request MUST contain the "schemas" attribute with the URI value of "urn:ietf:params:scim:api:messages:2.0:PatchOp". The body of an HTTP PATCH request MUST also contain the attribute "Operations", whose value is an array of one or more PATCH operations. Each PATCH operation object MUST have exactly one "op" member. Its value says what operation to perform, and it MAY be one of "add", "remove", or "replace". The semantics of each operation are covered in the subsections below π
Here's a basic look at the JSON structure of a PATCH request (non-normative) π
{ "schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[
{
"op":"add",
"path":"members",
"value":[
{
"display": "Babs Jensen",
"$ref":
"https://example.com/v2/Users/2819c223...413861904646",
"value": "2819c223-7f76-453a-919d-413861904646"
}
]
},
... + additional operations if needed ...
]
}
Figure 6: Example JSON Body for SCIM PATCH Request
The "path" attribute is a String that holds an attribute path describing the target of the operation. It's OPTIONAL for "add" and "replace", but it's REQUIRED for "remove" operations. Check the operation sections below for the details π§
The "path" attribute is described by this ABNF syntax rule:
PATH = attrPath / valuePath [subAttr]
Figure 7: SCIM PATCH PATH Rule
The ABNF rules "attrPath", "valuePath", and "subAttr" are defined in Section 3.4.2.2. The "valuePath" rule lets you pick out specific values of a complex multi-valued attribute π
Valid "path" examples look like this:
"path":"members"
"path":"name.familyName"
"path":"addresses[type eq \"work\"]"
"path":"members[value eq
\"2819c223-7f76-453a-919d-413861904646\"]"
"path":"members[value eq
\"2819c223-7f76-453a-919d-413861904646\"].displayName"
Figure 8: Example Path Values
Every operation against an attribute MUST be compatible with the attribute's mutability and schema, as defined in Sections 2.2 and 2.3 of [RFC7643] π For example, a client MUST NOT modify an attribute whose mutability is "readOnly" or "immutable". However, a client MAY "add" a value to an "immutable" attribute if that attribute had no previous value. An operation that isn't compatible with an attribute's mutability or schema SHALL return the appropriate HTTP response status code and a JSON detail error response, as defined in Section 3.12 π
The attribute notation rules in Section 3.10 apply when describing attribute paths. For all operations, the value of the "schemas" attribute on the SCIM service provider's representation of the resource SHALL be assumed by default. If one of the PATCH operations modifies the "schemas" attribute, the operations after it SHALL assume that modified state. Clients MAY implicitly modify the "schemas" attribute by adding (or replacing) an attribute using its fully qualified name, including the schema URN. For example, adding the attribute urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeNumber automatically adds the value urn:ietf:params:scim:schemas:extension:enterprise:2.0:User to the resource's "schemas" attribute π§©
Each PATCH operation is a single action applied to the same SCIM resource specified by the request URI. Operations run sequentially, in the order they appear in the array. Each operation is applied to the target resource, and the resulting resource becomes the target of the next operation. Evaluation keeps going until all operations are successfully applied or until an error condition shows up πββοΈπ¨
For multi-valued attributes, a PATCH operation that sets a value's "primary" sub-attribute to "true" SHALL cause the server to automatically set "primary" to "false" for any other values in the array. Only one primary, bestie π
A PATCH request SHALL be treated as atomic, no matter how many operations it has. If a single operation hits an error condition, the original SCIM resource MUST be restored, and a failure status SHALL be returned. all or nothing, no half-finished patches π«
If a request fails, the server SHALL return an HTTP response status code and a JSON detail error response, as defined in Section 3.12 π¨
On successful completion, the server either MUST return a 200 OK response code and the entire resource within the response body, subject to the "attributes" query parameter (see Section 3.9), or MAY return HTTP status code 204 (No Content) along with the appropriate response headers for a successful PATCH request. The server MUST return a 200 OK if the "attributes" parameter is specified in the request β¨
3.5.2.1. Add Operation β¨
okay so the add op is how you slide a brand new attribute value onto a resource that already exists π
the op MUST contain a value member π«Ά (no skipping this, bestie) and that's where the value you want to add goes. the value MAY be a quoted value, or it may be a JSON object holding the sub-attributes of the complex attribute named in the operation's path π
what actually happens depends on what the path is pointing at π
- If
pathis omitted, the target is the resource itself. Thevalueparameter holds a set of attributes to add to the resource. - If the target location does not exist, the attribute and value get added.
- If the target is a complex attribute, a set of sub-attributes SHALL be specified in the
valueparameter. - If the target is a multi-valued attribute, a new value gets added to it.
- If the target is a single-valued attribute, the existing value gets replaced.
- If the target is an attribute with no value yet, the attribute gets added with the new value.
- If the target location exists, the value gets replaced.
- If the target already has the value you specified, no changes SHOULD be made to the resource, and a success response SHOULD be returned. Unless other operations change the resource, this operation SHALL NOT change the modify timestamp of the resource. π°οΈβ¨
here's an example of adding a member to a group. some text got trimmed for readability (that's what the "..." is for) π§
PATCH /Groups/acbf3ae7-8463-...-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{ "schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[
{
"op":"add",
"path":"members",
"value":[
{
"display": "Babs Jensen",
"$ref":
"https://example.com/v2/Users/2819c223...413861904646",
"value": "2819c223-7f76-453a-919d-413861904646"
}
]
}
]
}
if Babs was already a member, nothing should change and you still get a success back π the server replies with either the whole updated Group or no body at all:
HTTP/1.1 204 No Content
Authorization: Bearer h480djs93hd8
ETag: W/"b431af54f0671a2"
Location:
"https://example.com/Groups/acbf3ae7-8463-...-9b4da3f908ce"
next up, adding one or more attributes to a User resource without using a path π
PATCH /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[{
"op":"add",
"value":{
"emails":[
{
"value":"babs@jensen.org",
"type":"home"
}
],
"nickname":"Babs"
}]
}
so in this one, an extra value gets added to the multi-valued emails attribute π§ and nickname gets added to the User. if there was already a nickname, it just gets replaced, same as the single-valued rules above πΈ
3.5.2.2. Remove Operation ποΈ
the remove op takes the value at the target location and yeets it. the path is REQUIRED here, and what happens depends on what it points to π
Hold on, I need to keep the BCP 14 words exact. Correcting that line to match the original (it's not a key word there, so plain text is right):
- If
pathis unspecified, the operation fails with HTTP status code 400 and ascimTypeerror code ofnoTarget. π« - If the target location is a single-value attribute, the attribute and its associated value are removed, and the attribute SHALL be considered unassigned.
- If the target location is a multi-valued attribute and no filter is specified, the attribute and all values are removed, and the attribute SHALL be considered unassigned.
- If the target location is a multi-valued attribute and a complex filter is specified comparing a
value, the values matched by the filter are removed. If no other values remain after removal of the selected values, the multi-valued attribute SHALL be considered unassigned. - If the target location is a complex multi-valued attribute and a complex filter is specified based on the attribute's sub-attributes, the matching records are removed. Sub-attributes whose values have been removed SHALL be considered unassigned. If the complex multi-valued attribute has no remaining records, the attribute SHALL be considered unassigned.
if an attribute gets removed or becomes unassigned and it's defined as a required attribute or a read-only attribute, the server SHALL return an HTTP response status code and a JSON detail error response as defined in Section 3.12, with a scimType error code of mutability. that's a hard no from the server π¨
here's how you remove a single member from a group. same deal as before, the display sub-attribute is optional π if the user wasn't in the group, nothing should change and you still get a success back.
server responses are left out for the rest of the PATCH examples so we don't drown in text π
PATCH /Groups/acbf3ae7-8463-...-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[{
"op":"remove",
"path":"members[value eq \"2819c223-7f76-...413861904646\"]"
}]
}
and this one removes all the members of a group π«§
PATCH /Groups/acbf3ae7-8463-...-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{ "schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[{
"op":"remove","path":"members"
}]
}
removing a value from a complex multi-valued attribute (request headers cut for brevity) π
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op":"remove",
"path":"emails[type eq \"work\" and value ew \"example.com\"]"
}]
}
and here's a request that removes one member and adds another, all in one go. some text got trimmed again (hello, "...") π
PATCH /Groups/acbf3ae7-8463-...-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{ "schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op":"remove",
"path":
"members[value eq\"2819c223...919d-413861904646\"]"
},
{
"op":"add",
"path":"members",
"value": [
{
"display": "James Smith",
"$ref":
"https://example.com/v2/Users/08e1d05d...473d93df9210",
"value": "08e1d05d...473d93df9210"
}
]
}
]
}
last one for this part: replacing ALL the members of a group with a brand new list π¦ the ops run in order, so remove first, then add π
PATCH /Groups/acbf3ae7-8463-4692-b4fd-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op":"remove","path":"members"
},
{
"op":"add",
"path":"members",
"value":[
{
"display": "Babs Jensen",
"$ref":
"https://example.com/v2/Users/2819c223...413861904646",
"value": "2819c223-7f76-453a-919d-413861904646"
},
{
"display": "James Smith",
"$ref":
"https://example.com/v2/Users/08e1d05d...473d93df9210",
"value": "08e1d05d-121c-4561-8b96-473d93df9210"
}]
}
]
}
3.5.2.3. Replace Operation β¨
okay so the "replace" operation is basically the glow-up button π
it swaps out the value at whatever spot the "path" points to. what it actually does depends on where that path lands π
- If the
"path"parameter is omitted, the target is assumed to be the resource itself. In this case, the"value"attribute SHALL contain a list of one or more attributes that are to be replaced. - If the target location is a single-value attribute, the attribute's value is replaced.
- If the target location is a multi-valued attribute and no filter is specified, the attribute and all of its values are replaced.
- If the target location path specifies an attribute that does not exist, the service provider SHALL treat the operation as an
"add". - If the target location specifies a complex attribute, a set of sub-attributes SHALL be specified in the
"value"parameter. This replaces any existing values, or adds them where an attribute did not previously exist. Sub-attributes that are not specified in the"value"parameter are left unchanged. - If the target location is a multi-valued attribute and a value selection (
"valuePath") filter is specified that matches one or more values of the multi-valued attribute, then all matching record values SHALL be replaced. - If the target location is a complex multi-valued attribute with a value selection filter (
"valuePath") and a specific sub-attribute (e.g.,"addresses[type eq \"work\"].streetAddress"), the matching sub-attribute of all matching records is replaced. - If the target location is a multi-valued attribute for which a value selection filter (
"valuePath") has been supplied and no record match was made, the service provider SHALL indicate failure by returning HTTP status code 400 and a"scimType"error code of"noTarget".
okay this next one is so satisfying π«Ά it shows how to replace all of the members of a group with a brand new members list, all in one single replace operation. some text was removed for readability (that's what the "..." is for) πΈ
PATCH /Groups/acbf3ae7-8463-4692-b4fd-9b4da3f908ce
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op":"replace",
"path":"members",
"value":[
{
"display": "Babs Jensen",
"$ref":
"https://example.com/v2/Users/2819c223...413861904646",
"value": "2819c223...413861904646"
},
{
"display": "James Smith",
"$ref":
"https://example.com/v2/Users/08e1d05d...473d93df9210",
"value": "08e1d05d...473d93df9210"
}
]
}]
}
this one is giving "change a whole work address" energy π‘ it uses a "valuePath" filter to pick the right address. heads up though, setting "primary" to "true" means the service provider will reset "primary" to "false" on any other existing "addresses" values. main character moves only π
PATCH /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op":"replace",
"path":"addresses[type eq \"work\"]",
"value":
{
"type": "work",
"streetAddress": "911 Universal City Plaza",
"locality": "Hollywood",
"region": "CA",
"postalCode": "91608",
"country": "US",
"formatted":
"911 Universal City Plaza\nHollywood, CA 91608 US",
"primary": true
}
}]
}
now this one is so precise π― it changes just one sub-attribute, "streetAddress", of the complex attribute "addresses", picked out by a "valuePath" filter.
PATCH /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op":"replace",
"path":"addresses[type eq \"work\"].streetAddress",
"value":"1010 Broadway Ave"
}]
}
last replace example, and it's a vibe β¨ it replaces all the values of one or more specific attributes on a User resource. other attributes are unaffected, so nothing else gets touched π«Ά
PATCH /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
If-Match: W/"a330bc54f0671c9"
{
"schemas":
["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [{
"op":"replace",
"value":{
"emails":[
{
"value":"bjensen@example.com",
"type":"work",
"primary":true
},
{
"value":"babs@jensen.org",
"type":"home"
}
],
"nickname":"Babs"
}]
}
3.6. Deleting Resources ποΈ
clients ask for a resource to be removed using DELETE π service providers MAY choose not to permanently delete the resource, but they MUST return a 404 (Not Found) error code for all operations tied to the previously deleted resource. they MUST also omit the resource from future query results π on top of that, the service provider SHOULD NOT count the deleted resource in conflict calculation. for example, if a User resource is deleted, a CREATE request for a User with the same userName as the deleted one SHOULD NOT fail with a 409 error because of a userName conflict. it's giving second chance π¦
DELETE /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Authorization: Bearer h480djs93hd8
If-Match: W/"c310cd84f0281b7"
when a DELETE goes through successfully, the server SHALL return a successful HTTP status code 204 (No Content). here's a non-normative example response π
HTTP/1.1 204 No Content
example: the client tries to retrieve the User that was just deleted π
GET /Users/2819c223-7f76-453a-919d-413861904646
Host: example.com
Authorization: Bearer h480djs93hd8
server response:
HTTP/1.1 404 Not Found
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":"Resource 2819c223-7f76-453a-919d-413861904646 not found",
"status": "404"
}
3.7. Bulk Operations π§
bulk operations are an optional server feature that lets clients send a potentially huge pile of resource operations in one single request π clients can find out whether bulk requests are supported by querying the service provider configuration (see Section 4). the body of a bulk operation holds a set of HTTP resource operations, using one of the HTTP methods the API supports: POST, PUT, PATCH, or DELETE.
bulk requests are identified with the schema URI "urn:ietf:params:scim:api:messages:2.0:BulkRequest", and bulk responses are identified with "urn:ietf:params:scim:api:messages:2.0:BulkResponse". bulk requests and bulk responses share a lot of attributes π unless it says otherwise, each attribute below shows up in both of them.
the following singular attribute is defined, on top of the common attributes from [RFC7643]:
- failOnErrors: an integer for the number of errors the service provider will accept before the operation gets terminated and an error response comes back. OPTIONAL in a request. Not valid in a response.
the following complex multi-valued attribute is defined, also on top of the common attributes from [RFC7643] πΈ
- Operations: defines the operations inside a bulk job. Each operation corresponds to a single HTTP request against a resource endpoint. REQUIRED. The Operations attribute has these sub-attributes:
- method: the HTTP method of the current operation. The possible values are
"POST","PUT","PATCH", or"DELETE". REQUIRED. - bulkId: the transient identifier of a newly created resource. It's unique within a bulk request and created by the client. The bulkId acts as a surrogate resource id, so clients can spot newly created resources in the response and cross-reference them in and across operations within a bulk request. REQUIRED when
"method"is"POST". - version: the current resource version. Version MAY be used if the service provider supports entity-tags (ETags) (Section 2.3 of [RFC7232]) and
"method"is"PUT","PATCH", or"DELETE". - path: the resource's relative path to the SCIM service provider's root. If
"method"is"POST", the value must specify a resource type endpoint, e.g.,/Usersor/Groups. All other"method"values must specify the path to a specific resource, e.g.,/Users/2819c223-7f76-453a-919d-413861904646. REQUIRED in a request. - data: the resource data as it would appear for a single SCIM POST, PUT, or PATCH operation. REQUIRED in a request when
"method"is"POST","PUT", or"PATCH". - location: the resource endpoint URL. REQUIRED in a response, except in the event of a POST failure.
- response: the HTTP response body for the specified request operation. When indicating a response with an HTTP status other than a 200-series response, the response body MUST be included. For normal completion, the server MAY elect to omit the response body.
- status: the HTTP response status code for the requested operation. When indicating an error, the
"response"attribute MUST contain the detailed error response as per Section 3.12.
- method: the HTTP method of the current operation. The possible values are
okay here's the big rule π if a bulk job is processed successfully, HTTP response code 200 OK MUST be returned. otherwise, an appropriate HTTP error code MUST be returned.
the service provider MUST keep doing as many changes as it can and disregard partial failures π₯ the client MAY override this by specifying a value for the "failOnErrors" attribute. "failOnErrors" sets how many errors the service provider should accept before it fails the remaining operations and returns the response.
to be able to reference a newly created resource, the bulkId attribute MAY be specified when creating new resources. The "bulkId" is defined by the client as a surrogate identifier in a POST operation (see Section 3.7.2). The service provider MUST return the same "bulkId" together with the newly created resource. Then the client can use that "bulkId" to map the service provider's id to the "bulkId" of the created resource π§β¨
a SCIM service provider MAY elect to optimize the sequence of operations it receives, like to improve processing performance π when it does, the service provider MUST make sure the client's intent is preserved and the same stateful result is achieved as for non-optimized processing. for example, before a "User" can be added to a "Group", they must first be created. processing these requests out of order might result in a failure to add the new "User" to the "Group" π
3.7.1. Circular Reference Processing β¨
Okay bestie, the service provider MUST try to resolve circular cross-references between resources in a single bulk job π, but it MAY stop after a failed attempt and just return HTTP status code 409 (Conflict) instead π. Here's the potential conflict in action:
POST /v2/Bulk
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Groups",
"bulkId": "qwerty",
"data": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Group A",
"members": [
{
"type": "Group",
"value": "bulkId:ytrewq"
}
]
}
},
{
"method": "POST",
"path": "/Groups",
"bulkId": "ytrewq",
"data": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Group B",
"members": [
{
"type": "Group",
"value": "bulkId:qwerty"
}
]
}
}
]
}
If the service provider manages to resolve those circular references, a later GET request comes back looking like this π¦:
GET /v2/Groups?filter=displayName sw 'Group'
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 2,
"Resources": [
{
"id": "c3a26dd3-27a0-4dec-a2ac-ce211e105f97",
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Group A",
"meta": {
"resourceType": "Group",
"created": "2011-08-01T18:29:49.793Z",
"lastModified": "2011-08-01T18:29:51.135Z",
"location":
"https://example.com/v2/Groups/c3a26dd3-27a0-4dec-a2ac-ce211e105f97",
"version": "W\/\"mvwNGaxB5SDq074p\""
},
"members": [
{
"value": "6c5bb468-14b2-4183-baf2-06d523e03bd3",
"$ref":
"https://example.com/v2/Groups/6c5bb468-14b2-4183-baf2-06d523e03bd3",
"type": "Group"
}
]
},
{
"id": "6c5bb468-14b2-4183-baf2-06d523e03bd3",
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Group B",
"meta": {
"resourceType": "Group",
"created": "2011-08-01T18:29:50.873Z",
"lastModified": "2011-08-01T18:29:50.873Z",
"location":
"https://example.com/v2/Groups/6c5bb468-14b2-4183-baf2-06d523e03bd3",
"version": "W\/\"wGB85s2QJMjiNnuI\""
},
"members": [
{
"value": "c3a26dd3-27a0-4dec-a2ac-ce211e105f97",
"$ref":
"https://example.com/v2/Groups/c3a26dd3-27a0-4dec-a2ac-ce211e105f97",
"type": "Group"
}
]
}
]
}
3.7.2. "bulkId" Temporary Identifiers π§
Okay so, a SCIM client can, within one bulk operation, create a new "User", create a new "Group", and add that brand-new "User" to that brand-new "Group" π. To pull this off, the client has to use the surrogate id attribute, "bulkId", to reference the User. The "bulkId" attribute value gets the literal "bulkId:" prefix stuck on the front. For example, if the bulkId is 'qwerty', the value is "bulkId:qwerty". The service provider MUST replace the string "bulkId:qwerty" with the permanent resource id once the resource is created β¨.
If the client wants multiple separate requests, each one gets its own "bulkId". So the SCIM client just gives each separate request a different "bulkId" value π .
Here's a slay example that creates a User with the "userName" 'Alice' and a "Group" with a "displayName" of "Tour Guides", with Alice as a member π. Notice that each operation has its own "bulkId" value. The second operation (whose "bulkId" is "ytrewq") points at the "bulkId" of "qwerty" so it can add Alice to the new 'Tour Guides' group π«Ά.
POST /v2/Bulk
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty",
"data": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "Alice"
}
},
{
"method": "POST",
"path": "/Groups",
"bulkId": "ytrewq",
"data": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "Tour Guides",
"members": [
{
"type": "User",
"value": "bulkId:qwerty"
}
]
}
}
]
}
The service provider sends back this response πΈ:
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"],
"Operations": [
{
"location":
"https://example.com/v2/Users/92b725cd-9465-4e7d-8c16-01f8e146b87a",
"method": "POST",
"bulkId": "qwerty",
"version": "W\/\"4weymrEsh5O6cAEK\"",
"status": {
"code": "201"
}
},
{
"location":
"https://example.com/v2/Groups/e9e30dba-f08f-4109-8486-d5c6a331660a",
"method": "POST",
"bulkId": "ytrewq",
"version": "W\/\"lha5bbazU3fNvfe5\"",
"status": {
"code": "201"
}
}
]
}
In that example, the "Alice" User resource has an "id" of "92b725cd-9465-4e7d-8c16-01f8e146b87a", and the 'Tour Guides' Group has an "id" of "e9e30dba-f08f-4109-8486-d5c6a331660a" π.
A later GET request for the 'Tour Guides' Group (the one with that "id" of "e9e30dba-f08f-4109-8486-d5c6a331660a") returns the following, and look at that, Alice's "id" is now the value for the member in the Group 'Tour Guides' ππ₯:
HTTP/1.1 200 OK
Content-Type: application/scim+json
Location:
https://example.com/v2/Groups/e9e30dba-f08f-4109-8486-d5c6a331660a
ETag: W/"lha5bbazU3fNvfe5"
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "e9e30dba-f08f-4109-8486-d5c6a331660a",
"displayName": "Tour Guides",
"meta": {
"resourceType": "Group",
"created": "2011-08-01T18:29:49.793Z",
"lastModified": "2011-08-01T20:31:02.315Z",
"location":
"https://example.com/v2/Groups/e9e30dba-f08f-4109-8486-d5c6a331660a",
"version": "W\/\"lha5bbazU3fNvfe5\""
},
"members": [
{
"value": "92b725cd-9465-4e7d-8c16-01f8e146b87a",
"$ref":
"https://example.com/v2/Users/92b725cd-9465-4e7d-8c16-01f8e146b87a",
"type": "User"
}
]
}
Extensions that include references to other resources MUST be handled in the same way by the service provider π¦. Here's an example that uses the bulkId attribute inside the enterprise extension managerId attribute π:
POST /v2/Bulk
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "qwerty",
"data": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "Alice"
}
},
{
"method": "POST",
"path": "/Users",
"bulkId": "ytrewq",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"userName": "Bob",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "11250",
"manager": {
"value": "bulkId:qwerty"
}
}
}
}
]
}
3.7.3. Response and Error Handling β¨
okay so the service provider response MUST include the result of every processed operation, bestie π
a location attribute with the resource's endpoint MUST be returned for all operations except failed POST operations (which have no location π). the status attribute is the tea on whether one operation inside the bulk job worked or flopped. the status MUST include the code attribute, which holds the HTTP response code you'd have gotten if you'd sent a single HTTP request instead π§. and if an error happened, the status MUST also include the description attribute, a human-readable explanation of what went wrong π
"status": "201"
here's a failed operation's status. it's giving drama π
"status": "400",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType":"invalidSyntax"
"detail":
"Request is unparsable, syntactically incorrect, or violates schema.",
"status":"400"
}
okay now the fun part π this example shows how to add, update, and remove a user all in one go. the failOnErrors attribute is set to '1', which means the service provider stops processing and hands back results after one error. the POST's bulkId is 'qwerty', so the client can match the new User to the returned resource id of "92b725cd-9465-4e7d-8c16-01f8e146b87a" β¨
POST /v2/Bulk
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"failOnErrors":1,
"Operations":[
{
"method":"POST",
"path":"/Users",
"bulkId":"qwerty",
"data":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:User"],
"userName":"Alice"
}
},
{
"method":"PUT",
"path":"/Users/b7c14771-226c-4d05-8860-134711653041",
"version":"W\/\"3694e05e9dff591\"",
"data":{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"b7c14771-226c-4d05-8860-134711653041",
"userName":"Bob"
}
},
{
"method": "PATCH",
"path": "/Users/5d8d29d3-342c-4b5f-8683-a3cb6763ffcc",
"version": "W/\"edac3253e2c0ef2\"",
"data": {[
{
"op": "remove",
"path": "nickName"
},
{
"op": "add",
"path": "userName",
"value": "Dave"
}
]}
},
{
"method":"DELETE",
"path":"/Users/e9025315-6bea-44e1-899c-1e07454e468b",
"version":"W\/\"0ee8add0a938e1a\""
}
]
}
the service provider returns this response π¦
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"],
"Operations": [
{
"location":
"https://example.com/v2/Users/92b725cd-9465-4e7d-8c16-01f8e146b87a",
"method": "POST",
"bulkId": "qwerty",
"version": "W\/\"oY4m4wn58tkVjJxK\"",
"status": "201"
},
{
"location":
"https://example.com/v2/Users/b7c14771-226c-4d05-8860-134711653041",
"method": "PUT",
"version": "W\/\"huJj29dMNgu3WXPD\"",
"status": "200"
},
{
"location":
"https://example.com/v2/Users/5d8d29d3-342c-4b5f-8683-a3cb6763ffcc",
"method": "PATCH",
"version": "W\/\"huJj29dMNgu3WXPD\"",
"status": "200"
},
{
"location":
"https://example.com/v2/Users/e9025315-6bea-44e1-899c-1e07454e468b",
"method": "DELETE",
"status": "204"
}
]
}
and if something goes wrong while creating the User 'Alice', the service provider stops processing and immediately sends back a response. it includes the error plus any successful results from before the error π€
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"],
"Operations": [
{
"method": "POST",
"bulkId": "qwerty",
"status": "400",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType":"invalidSyntax"
"detail":
"Request is unparsable, syntactically incorrect, or violates schema.",
"status":"400"
}
}
]
}
if failOnErrors isn't specified, or the service provider hasn't hit the error limit the client set, the service provider keeps going and processes all the operations π here's a case where everything failed π
HTTP/1.1 200 OK
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkResponse"],
"Operations": [
{
"method": "POST",
"bulkId": "qwerty",
"status": "400",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType":"invalidSyntax"
"detail":
"Request is unparsable, syntactically incorrect, or violates schema.",
"status":"400"
}
},
{
"location":
"https://example.com/v2/Users/b7c14771-226c-4d05-8860-134711653041",
"method": "PUT",
"status": "412",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":
"Failed to update. Resource changed on the server.",
"status":"412"
}
},
{
"location":
"https://example.com/v2/Users/5d8d29d3-342c-4b5f-8683-a3cb6763ffcc",
"method": "PATCH",
"status": "412",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":
"Failed to update. Resource changed on the server.",
"status":"412"
}
},
{
"location":
"https://example.com/v2/Users/e9025315-6bea-44e1-899c-1e07454e468b",
"method": "DELETE",
"status": "404",
"response":{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":"Resource does not exist.",
"status":"404"
}
}
]
}
3.7.4. Maximum Operations π
the service provider MUST define the maximum number of operations and the maximum payload size a client can send in a single request π«Ά these limits MAY be retrieved from the service provider configuration (see 'bulk' in Sections 5 and 8.5 of [RFC7643]). if either limit gets exceeded, the service provider MUST return HTTP response code 413 (Payload Too Large). and the returned response MUST specify which limit was exceeded in the body of the error response. no sneaking past the bouncer π«
in this example, the client sent a request way over the service provider's maximum payload size of 1 megabyte π
POST /v2/Bulk
Host: example.com
Accept: application/scim+json
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: 4294967296
...
the server sends this error back for the oversized request π
HTTP/1.1 413 Payload Too Large
Content-Type: application/scim+json
{
"schemas":["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "413",
"detail":
"The size of the bulk operation exceeds the maxPayloadSize (1048576)."
}
3.8. Data Input/Output Formats π
servers MUST accept requests and be able to return JSON-structured responses using UTF-8 encoding [RFC3629]. UTF-8 SHALL be the default encoding format π other media types MAY be supported by service providers, but they're beyond the scope of this specification.
clients using other encodings MUST specify the format the data is submitted in, via an HTTP Content-Type header as described in Section 3.1.1.5 of [RFC7231]. they MAY also specify the desired response format via an HTTP Accept header (Section 5.3.2 of [RFC7231]), e.g., Accept: application/scim+json, or via a URI suffix, like this π§
GET /Users/2819c223-7f76-453a-919d-413861904646.scim
Host: example.com
service providers MUST support the Accept header Accept: application/scim+json and SHOULD support Accept: application/json. both of these mean JSON documents conforming to [RFC7159] πΈ the format defaults to application/scim+json if nothing else is specified, so no stress β¨
singular attributes are encoded as string name-value pairs in JSON, like this π
"attribute": "value"
multi-valued attributes are encoded as arrays in JSON π
"attributes": [ "value1", "value2" ]
and elements with nested elements are represented as objects in JSON π§
"attribute": { "subattribute1": "value1", "subattribute2": "value2" }
3.9. Additional Operation Response Parameters π¦
for any SCIM operation where a resource representation comes back (think HTTP GET), the attributes you get back are the minimum attribute set plus the default attribute set π the minimum set is the attributes with their "returned" characteristic set to "always" (see Section 2.2 of [RFC7643]). the default attribute set is the attributes with the "returned" characteristic set to "default" π
clients MAY ask for a partial resource representation on any operation that returns a resource in the response. they do that with either of the mutually exclusive URL query parameters "attributes" or "excludedAttributes", like so β¨
attributes: when this is specified, the default list of attributes SHALL be overridden, and each resource returned MUST contain the minimum set of resource attributes plus any attributes or sub-attributes explicitly requested by the "attributes" parameter. the query parameter attributes value is a comma-separated list of resource attribute names in standard attribute notation (Section 3.10) form (e.g., userName, name, emails). πexcludedAttributes: when this is specified, each resource returned MUST contain the minimum set of resource attributes. on top of that, the default set of attributes minus the ones listed in "excludedAttributes" is returned. the query parameter attributes value is a comma-separated list of resource attribute names in standard attribute notation (Section 3.10) form (e.g., userName, name, emails). π
here's a request asking for just the userName π
GET /Users/2819c223-7f76-453a-919d-413861904646?attributes=userName
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
and the response that comes back π«Ά
HTTP/1.1 200 OK
Content-Type: application/scim+json
Location:
https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646
ETag: W/"a330bc54f0671c9"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"userName":"bjensen"
}
3.10. Attribute Notation π
okay so every SCIM operation uses the same naming system for attributes, and it's giving organized π
. You put the schema URN in front of the attribute name, separated by a colon (":") character. So the core User attribute userName becomes urn:ietf:params:scim:schemas:core:2.0:User:userName π. Clients MAY leave off the core schema attribute URN prefixes, but they SHOULD fully qualify extended attributes with the associated schema extension URN so nobody gets mixed up about naming conflicts π.
For example, the age attribute from urn:ietf:params:scim:schemas:exampleCo:2.0:hr is uniquely identified as urn:ietf:params:scim:schemas:exampleCo:2.0:hr:age β¨.
Sub-attributes of complex attributes use nested dot (".") notation, so it's {urn}:{Attribute name}.{Sub-Attribute name} π§. The fully qualified path for a User's givenName is urn:ietf:params:scim:schemas:core:2.0:User:name.givenName π. Every facet of the fully encoded name (the URN, the attribute name, and the sub-attribute name) is case insensitive, so no capitalisation drama here, bestie πΈ.
3.11. "/Me" Authenticated Subject Alias π¦
a client MAY use a URL shaped like <base-URI>/Me as a URI alias for the User (or other resource) tied to whoever is currently authenticated, for any SCIM operation. it's giving main character energy π. A service provider MAY respond in one of three ways:
- A service provider that does NOT support this feature SHOULD respond with HTTP status code 501 (Not Implemented) π .
- A service provider MAY choose to redirect the client using HTTP status code 308 (Permanent Redirect) to the resource associated with the authenticated subject. The client MAY then repeat the request at the indicated location π.
- A service provider MAY process the SCIM request directly. In any response, the HTTP "Location" header MUST be the permanent location of the aliased resource associated with the authenticated subject π.
When you use the SCIM Create Resource command (HTTP POST) with the /Me alias, the resourceType being created is up to the service provider. It depends on who is making the request (if they're not anonymous) and on the request body attributes, like schemas π. See Section 7.6 for the security considerations for this one, because it's serious π.
3.12. HTTP Status and Error Response Handling π
SCIM uses the HTTP response status codes defined in Section 6 of [RFC7231] to say whether an operation worked or flopped β¨. On top of the status code, implementers MUST return the errors in the body of the response in JSON format, using the attributes below π
. Error responses are identified with this schema URI: urn:ietf:params:scim:api:messages:2.0:Error π«Ά. A SCIM error response with a JSON body has these attributes:
status: the HTTP status code (see Section 6 of [RFC7231]), written as a JSON string. REQUIRED π₯.scimType: a SCIM detail error keyword. See Table 9. OPTIONAL π.detail: a detailed human-readable message. OPTIONAL π¬.
Implementers SHOULD handle the HTTP status codes below the way the table describes π§.
+----------------+---------------+----------------------------------+
| Status | Applicability | Suggested Explanation |
+----------------+---------------+----------------------------------+
| 307 (Temporary | GET, POST, | The client is directed to repeat |
| Redirect) | PUT, PATCH, | the same HTTP request at the |
| | DELETE | location identified. The client |
| | | SHOULD NOT use the location |
| | | provided in the response as a |
| | | permanent reference to the |
| | | resource and SHOULD continue to |
| | | use the original request URI |
| | | [RFC7231]. |
| | | |
| 308 (Permanent | GET, POST, | The client is directed to repeat |
| Redirect) | PUT, PATCH, | the same HTTP request at the |
| | DELETE | location identified. The client |
| | | SHOULD use the location provided |
| | | in the response as the permanent |
| | | reference to the resource |
| | | [RFC7538]. |
| | | |
| 400 (Bad | GET, POST, | Request is unparsable, |
| Request) | PUT, PATCH, | syntactically incorrect, or |
| | DELETE | violates schema. |
| | | |
| 401 | GET, POST, | Authorization failure. The |
| (Unauthorized) | PUT, PATCH, | authorization header is invalid |
| | DELETE | or missing. |
| | | |
| 403 | GET, POST, | Operation is not permitted based |
| (Forbidden) | PUT, PATCH, | on the supplied authorization. |
| | DELETE | |
| | | |
| 404 (Not | GET, POST, | Specified resource (e.g., User) |
| Found) | PUT, PATCH, | or endpoint does not exist. |
| | DELETE | |
| | | |
| 409 (Conflict) | POST, PUT, | The specified version number |
| | PATCH, DELETE | does not match the resource's |
| | | latest version number, or a |
| | | service provider refused to |
| | | create a new, duplicate |
| | | resource. |
| | | |
| 412 | PUT, PATCH, | Failed to update. Resource has |
| (Precondition | DELETE | changed on the server. |
| Failed) | | |
| | | |
| 413 (Payload | POST | {"maxOperations": |
| Too Large) | | 1000,"maxPayloadSize": 1048576} |
| | | |
| 500 (Internal | GET, POST, | An internal error. Implementers |
| Server Error) | PUT, PATCH, | SHOULD provide descriptive |
| | DELETE | debugging advice. |
| | | |
| 501 (Not | GET, POST, | Service provider does not |
| Implemented) | PUT, PATCH, | support the request operation, |
| | DELETE | e.g., PATCH. |
+----------------+---------------+----------------------------------+
Table 8: SCIM HTTP Status Code Usage
For HTTP status code 400 (Bad Request) responses, the following detail error types are defined π:
+---------------+--------------------------------+------------------+
| scimType | Description | Applicability |
+---------------+--------------------------------+------------------+
| invalidFilter | The specified filter syntax | GET (Section |
| | was invalid (does not comply | 3.4.2), POST |
| | with Figure 1), or the | (Search - |
| | specified attribute and filter | Section 3.4.3), |
| | comparison combination is not | PATCH (Path |
| | supported. | Filter - Section |
| | | 3.5.2) |
| | | |
| tooMany | The specified filter yields | GET (Section |
| | many more results than the | 3.4.2), POST |
| | server is willing to calculate | (Search - |
| | or process. For example, a | Section 3.4.3) |
| | filter such as "(userName pr)" | |
| | by itself would return all | |
| | entries with a "userName" and | |
| | MAY not be acceptable to the | |
| | service provider. | |
| | | |
| uniqueness | One or more of the attribute | POST (Create - |
| | values are already in use or | Section 3.3), |
| | are reserved. | PUT (Section |
| | | 3.5.1), PATCH |
| | | (Section 3.5.2) |
| | | |
| mutability | The attempted modification is | PUT (Section |
| | not compatible with the target | 3.5.1), PATCH |
| | attribute's mutability or | (Section 3.5.2) |
| | current state (e.g., | |
| | modification of an "immutable" | |
| | attribute with an existing | |
| | value). | |
| | | |
| invalidSyntax | The request body message | POST (Search - |
| | structure was invalid or did | Section 3.4.3, |
| | not conform to the request | Create - Section |
| | schema. | 3.3, Bulk - |
| | | Section 3.7), |
| | | PUT (Section |
| | | 3.5.1) |
| | | |
| invalidPath | The "path" attribute was | PATCH (Section |
| | invalid or malformed (see | 3.5.2) |
| | Figure 7). | |
| | | |
| noTarget | The specified "path" did not | PATCH (Section |
| | yield an attribute or | 3.5.2) |
| | attribute value that could be | |
| | operated on. This occurs when | |
| | the specified "path" value | |
| | contains a filter that yields | |
| | no match. | |
| | | |
| invalidValue | A required value was missing, | GET (Section |
| | or the value specified was not | 3.4.2), POST |
| | compatible with the operation | (Create - |
| | or attribute type (see Section | Section 3.3, |
| | 2.2 of [RFC7643]), or resource | Query - Section |
| | schema (see Section 4 of | 3.4.3), PUT |
| | [RFC7643]). | (Section 3.5.1), |
| | | PATCH (Section |
| | | 3.5.2) |
| | | |
| invalidVers | The specified SCIM protocol | GET (Section |
| | version is not supported (see | 3.4.2), POST |
| | Section 3.13). | (ALL), PUT |
| | | (Section 3.5.1), |
| | | PATCH (Section |
| | | 3.5.2), DELETE |
| | | (Section 3.6) |
| | | |
| sensitive | The specified request cannot | GET (Section |
| | be completed, due to the | 3.4.2) |
| | passing of sensitive (e.g., | |
| | personal) information in a | |
| | request URI. For example, | |
| | personal information SHALL NOT | |
| | be transmitted over request | |
| | URIs. See Section 7.5.2. | |
+---------------+--------------------------------+------------------+
Table 9: SCIM Detail Error Keyword Values
Note that in Table 9 above, the information in the Applicability column applies to the normal HTTP method but MAY apply within a SCIM bulk operation (via HTTP POST).
Here's what it looks like when you GET something that doesn't exist π:
HTTP/1.1 404 Not Found
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":"Resource 2819c223-7f76-453a-919d-413861904646 not found",
"status": "404"
}
And here's a PUT that gets bounced, because you can't mess with a readOnly attribute π ββοΈ:
HTTP/1.1 400 Bad Request
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"scimType":"mutability"
"detail":"Attribute 'id' is readOnly",
"status": "400"
}
3.13. SCIM Protocol Versioning β¨
Okay so the Base URL MAY be appended with a version identifier, as its own segment in the URL path π¦. At the time of this writing, the identifier is 'v2'. If you add one, it MUST show up in the URL path right before the resource endpoint, and it has to follow this pattern: the letter 'v' followed by the SCIM version number. Like, a version 'v2' User request is written as /v2/Users. When you include a version, service providers MUST perform the operation using that version or reject the request. When it's left out, service providers SHOULD use the most recent SCIM protocol version they support π.
3.14. Versioning Resources π
SCIM handles resource versioning with standard HTTP ETags (Section 2.3 of [RFC7232]) π§. Service providers MAY support weak ETags, which are the preferred tools for conditional retrievals and for making sure clients don't accidentally overwrite each other's changes π«Ά. When ETags are supported, SCIM ETags MUST be specified as an HTTP header and SHOULD also be specified within the 'version' attribute inside the resource's 'meta' attribute.
Here's an example create request π:
POST /Users HTTP/1.1
Host: example.com
Content-Type: application/scim+json
Authorization: Bearer h480djs93hd8
Content-Length: ...
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"bjensen",
"externalId":"bjensen",
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara"
}
}
The server responds with an ETag in both the response header and the meta structure π:
HTTP/1.1 201 Created
Content-Type: application/scim+json
Location:
https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646
ETag: W/"e180ee84f0671b1"
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"id":"2819c223-7f76-453a-919d-413861904646",
"meta":{
"resourceType":"User",
"created":"2011-08-01T21:32:44.882Z",
"lastModified":"2011-08-01T21:32:44.882Z",
"location":
"https://example.com/v2/Users/2819c223-7f76-453a-919d-413861904646",
"version":"W\/\"e180ee84f0671b1\""
},
"name":{
"formatted":"Ms. Barbara J Jensen III",
"familyName":"Jensen",
"givenName":"Barbara"
},
"userName":"bjensen"
}
With that returned ETag, clients MAY choose to retrieve the resource only if it has been modified π₯.
Here's an example of conditional retrieval using the If-None-Match header (Section 3.2 of [RFC7232]) π¦:
GET /Users/2819c223-7f76-453a-919d-413861904646?attributes=displayName
Host: example.com
Accept: application/scim+json
Authorization: Bearer h480djs93hd8
If-None-Match: W/"e180ee84f0671b1"
If the resource hasn't changed, the service provider just sends back an empty body with a 304 (Not Modified) response code π .
If the service provider supports versioning of resources, the client MAY supply an If-Match header (Section 3.1 of [RFC7232]) for PUT and PATCH operations. That way the requested operation only succeeds if the supplied ETag matches the latest service provider resource, e.g., If-Match: W/"e180ee84f0671b1" πΈ.
4. Service Provider Configuration Endpoints β¨
okay bestie, SCIM has three discovery endpoints π that help clients figure out what a service provider can do, and they MAY be fetched with HTTP GET. the MAY is doing a lot here π
/ServiceProviderConfig is the one that tells you which SCIM spec features a service provider has π. An HTTP GET to this endpoint returns a JSON structure describing those features. This endpoint SHALL return responses with a JSON object using a "schemas" attribute of "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig". The attributes in that JSON object are defined in Section 5 of [RFC7643], and there's an example representation in Section 8.5 of [RFC7643] π«Ά
/Schemas is for info about the resource schemas a service provider supports π. An HTTP GET to the endpoint "/Schemas" SHALL return all supported schemas in ListResponse format (see Figure 3). If you want one specific schema, you just tack its schema URI onto the end of /Schemas, like this:
/Schemas/urn:ietf:params:scim:schemas:core:2.0:User
The contents of each schema returned are described in Section 7 of [RFC7643], and an example representation of SCIM schemas is in Section 8.7 of [RFC7643] πΈ
/ResourceTypes tells you what types of resources exist on a SCIM service provider, like Users and Groups π§. Each resource type defines its endpoints, the core schema URI that defines the resource, and any supported schema extensions. The attributes that define a resource type are in Section 6 of [RFC7643], and an example representation is in Section 8.6 of [RFC7643].
Now, if a request is for one specific "ResourceType" or "Schema", the single JSON object comes back the same way a single User or Group would, as per Section 3.4.1 π. When returning multiple ResourceTypes or Schemas, the message form described by urn:ietf:params:scim:api:messages:2.0:ListResponse (ListResponse) SHALL be used, as shown in Figure 3 and in Figure 9 below. Query parameters from Section 3.4.2, like filtering, sorting, and pagination, SHALL be ignored. And if a "filter" is provided, the service provider SHOULD respond with HTTP status code 403 (Forbidden) π. Why? So clients can't wrongly assume that any matching conditions in a filter are true. no cap, that's a smart move.
Here's a non-normative example of an HTTP GET to the /ResourceTypes endpoint π:
{
"totalResults":2,
"itemsPerPage":10,
"startIndex":1,
"schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"Resources":[{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ResourceType"],
"id":"User",
"name":"User",
"endpoint": "/Users",
"description": "User Account",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User",
"schemaExtensions": [{
"schema":
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
"required": true
}],
"meta": {
"location":"https://example.com/v2/ResourceTypes/User",
"resourceType": "ResourceType"
}
},
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ResourceType"],
"id":"Group",
"name":"Group",
"endpoint": "/Groups",
"description": "Group",
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group",
"meta": {
"location":"https://example.com/v2/ResourceTypes/Group",
"resourceType": "ResourceType"
}
}]
}
Figure 9: Example Resource Type JSON Representation
5. Preparation and Comparison of Internationalized Strings π
okay so this part is about making usernames and passwords behave sensibly for people all over the world π. Typing and comparing internationalized strings can get messy, so there are rules for preparing, enforcing, and comparing them. Before comparing or checking the uniqueness of a "userName" or "password" attribute, service providers MUST use the PRECIS preparation and comparison rules in Sections 3 and 4 of [RFC7613], respectively. Those rules are based on the PRECIS framework specification [RFC7564]. For the "Case Mapping vs. Case Preparation" discussion about "userName" attributes, check out Section 3.4 of [RFC7613] π
6. Multi-Tenancy π°
a single service provider might serve the SCIM protocol to lots of clients π. Depending on the service, clients might be allowed to access and change resources that other clients made. Or they might each use totally separate sets of resources and expect that nobody else can see theirs. These setups are called "multi-tenancy", where each client is a "tenant" of the service provider (or represents one). Clients can also be multi-tenanted themselves π¦
These common cases might show up:
- All clients share all resources (no tenancy).
- Each single client creates and accesses a private subset of resources (1 client:1 Tenant).
- Sets of clients share sets of resources (M clients:1 Tenant).
- One client can create and access several private subsets of resources (1 client:M Tenants).
Service providers may implement any subset of the above cases π
Multi-tenancy is OPTIONAL. The SCIM protocol does not define a scheme for it.
The SCIM protocol also doesn't prescribe how clients and service providers handle these things:
- Registering or provisioning Tenants
- Associating a subset of clients with a subset of the Tenants
- Indicating which tenant is associated with the data in a request or response, or indicating which Tenant is the subject of a query
6.1. Associating Clients to Tenants
the service provider MAY use one of the authentication mechanisms from Section 2 to figure out who the client is, and then infer the Tenant they belong to π
if a client is linked to more than one Tenant, the service provider MAY use one of the three methods below to let the client explicitly say which Tenant it wants β¨
If any of these explicit methods are used, the service provider should make sure access controls are in place, so cross-tenant use cases are either blocked or allowed on purpose. the service provider should also think about precedence in cases where a client explicitly picks a Tenant but is implicitly associated with a different one π§
In all of these methods, {tenant_id} is a unique identifier for the Tenant, as defined by the service provider. The three methods are:
- A URL prefix:
https://www.example.com/Tenants/{tenant_id}/v2/Users - A sub-domain:
https://{tenant_id}.example.com/v2/Groups - An HTTP header: the service provider may recognize a
{tenant_id}provided by the client in an HTTP header as the indicator of the desired target Tenant π
6.2. SCIM Identifiers with Multiple Tenants
some things to keep in mind for a multi-tenant setup π:
- The service provider may choose to implement SCIM ids that are unique across all resources for all Tenants, but this is not required.
- The externalId, defined by the client, is required to be unique ONLY within the resources associated with the associated Tenant π
7. Security Considerations π
okay this section is serious, so no cap, read it all π
7.1. HTTP Considerations
The SCIM protocol layers on top of HTTP, so it inherits the security considerations of HTTP (Section 9 of [RFC7230]) and its related specifications.
As stated in Section 2.7.1 of [RFC7230], a SCIM client MUST NOT generate the "userinfo" (i.e., username and password) component (and its @ delimiter) when an "http" URI reference is generated with a message. userinfo and its @ delimiter are now disallowed in HTTP, so don't even try π
ββοΈ
7.2. TLS Support Considerations
SCIM resources (e.g., Users and Groups) contain sensitive information, including passwords π. Therefore, SCIM clients and service providers MUST require the use of a transport-layer security mechanism when communicating with SCIM service providers. The SCIM service provider MUST support TLS 1.2 [RFC5246] and MAY support additional transport-layer mechanisms that meet its security requirements. When using TLS, the client MUST perform a TLS/SSL server identity check, per [RFC6125]. For implementation security considerations for TLS, see [RFC7525] π‘οΈ
7.3. Authorization Token Considerations
When using authorization tokens such as those issued by OAuth 2.0 [RFC6749], implementers MUST take into account the threats and countermeasures documented in Section 8 of [RFC7521] π
7.4. Bearer Token and Cookie Considerations
Since possessing a bearer token or cookie MAY authorize the holder to potentially read, modify, or delete resources, bearer tokens and cookies MUST contain sufficient entropy to prevent a random guessing attack. For example, see Section 5.2 of [RFC6750] and Section 5.1.4.2.2 of [RFC6819] π₯Ί
As with all SCIM communications, bearer tokens and HTTP cookies MUST be exchanged using TLS.
Bearer tokens MUST have a limited lifetime, which the service provider can determine directly or indirectly (e.g., by checking with a validation service). By expiring tokens, clients are forced to obtain a new token (which usually involves re-authentication) for continued authorized access. For example, in OAuth 2.0, a client MAY use OAuth token refresh to get a new bearer token after authenticating to an authorization server. See Section 6 of [RFC6749] β³
As with bearer tokens, an HTTP cookie SHOULD last no longer than the lifetime of a browser session. An expiry time should be set that limits session cookie lifetime as per Section 5.2.1 of [RFC6265] πͺ
Implementations supporting OAuth bearer tokens need to factor in the security considerations of this authorization method [RFC7521]. Security is only as good as the weakest link, so implementers also need to consider the authentication choices coupled with OAuth bearer tokens. The security considerations of the default authentication method for OAuth bearer tokens, HTTP Basic, are well documented in [HTTP-BASIC-AUTH], so implementers are encouraged to use stronger authentication methods. Designating the specific methods of authentication and authorization is out of scope for SCIM, but this information is provided as a resource for implementers π
7.5. Privacy Considerations
7.5.1. Personal Information
The SCIM Core Schema specification [RFC7643] defines attributes that may contain personally identifying information, as well as other sensitive personal data. The privacy considerations in the Security Considerations section of [RFC7643] MUST be considered π«Ά
7.5.2. Disclosure of Sensitive Information in URIs π
Okay bestie, let's talk about what ends up sitting in a URI π. As mentioned in Section 9.4 of [RFC7231], SCIM clients that send query filters with HTTP GET SHOULD think about what's inside those filters and whether putting it in a URI could leak it through web browsers or server logs. Is that a privacy breach or a confidentiality fail? Totally worth checking π. This matters most when the info is legally "personally identifiable information" or is otherwise locked down by privacy laws π. In those cases, for maximum security and confidentiality, clients SHOULD query using HTTP POST (see Section 3.4.3) π.
Servers that get HTTP GET requests with filters holding sensitive or confidential personal info SHOULD reply with HTTP status code 403 to say the operation is forbidden π«. A "scimType" error code of "sensitive" may be returned to say the request has to be submitted using POST. Here's a non-normative example, so it's just vibes and not the rules β¨:
HTTP/1.1 403 Forbidden
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail":
"Query filter involving 'name' is restricted or confidential",
"scimType": "sensitive",
"status": "404"
}
7.6. Anonymous Requests π«£
If a SCIM service provider accepts anonymous requests, like SCIM resource creation requests sent via HTTP POST, appropriate security measures should be put in place to prevent or limit exposure to attacks π‘οΈ. The following countermeasures MAY be used:
- Authenticate the web user interface components that build the SCIM creation request. The end-user can stay anonymous, but the UI component usually has its own way to authenticate to the SCIM service provider (for example, an OAuth client credential [RFC6749]). It may also add its own checks, like a Completely Automated Public Turing test to tell Computers and Humans Apart (CAPTCHA), to make sure a legit request is being made π€.
- Limit the number of requests that any particular client MAY make in a period of time β³.
- For User resources, default newly created resources to an "active" setting of "false", and use a secondary confirmation process (e.g., email confirmation) to make sure the resource created is real π§.
7.7. Secure Storage and Handling of Sensitive Data π
An attacker might get valid username/password combos from the SCIM service provider's underlying database, either by getting into the database or by running injection attacks π±. That could lead to unintended disclosure of those combinations. The fallout can spread beyond the SCIM service provider if the data was provisioned from other domains.
Admins should follow industry best practices for protecting credential storage and, in particular, SHOULD follow the recommendations in Section 5.1.4.1 of [RFC6819]. Those recommendations include, but aren't limited to, the following:
- Provide injection attack countermeasures (e.g., by validating all inputs and parameters);
- Credentials should not be stored in cleartext form;
- Store credentials using an encrypted protection mechanism (e.g., hashing); and
- Where possible, avoid passwords as the sole form of authentication, and consider using credentials that are based on asymmetric cryptography.
As outlined in Section 5.1.4.2 of [RFC6819], administrators SHOULD take countermeasures like these to prevent online attacks on secrets π¨:
- Use a secure password policy to increase user password entropy, which makes online attacks and password guessing harder;
- Mitigate attacks on passwords by locking accounts that have a number of failed attempts;
- Use "tar pit" techniques by temporarily locking a respective account and delaying responses for a certain duration. The duration may increase with the number of failed attempts; and
- Use authentication systems that use CAPTCHAs and other factors for authenticating users, to further reduce the possibility of automated attacks.
Service providers SHOULD define an access control model that tells apart individual client applications and their specific need to access information, plus any User self-service rights to review and update personal profile info π . This may include OAuth 2.0 delegation profiles that let client systems act on behalf of users with their permission π«Ά.
7.8. Case-Insensitive Comparison and International Languages π
When comparing Unicode strings, such as in query filters or when testing for uniqueness of usernames and passwords, strings MUST be appropriately prepared before comparison. See Section 5 β¨.
8. IANA Considerations π
8.1. Media Type Registration π
Here's the registration template for the media type. It's the official paperwork, so I'm keeping every field exactly as it is ποΈ:
To: ietf-types@iana.org
Subject: Registration of media type application/scim+json
Type name: application
Subtype name: scim+json
Required parameters: none
Optional parameters: none
Encoding considerations: 8bit
Security considerations: See Section 7 of this document (RFC 7644)
Interoperability considerations: The "application/scim+json" media
type is intended to identify JSON structure data that conforms to
the SCIM protocol and schema specifications. Older versions of
SCIM are known to informally use "application/json".
Published specification: this document (RFC 7644)
Applications that use this media type: It is expected that
applications that use this type may be special-purpose
applications intended for inter-domain provisioning. Clients may
also be applications (e.g., mobile applications) that need to use
SCIM for self-registration of user accounts. SCIM services may be
offered by web applications that offer support for standards-based
provisioning or may be a dedicated SCIM service provider such as a
"cloud directory". Content may be treated as equivalent to the
"application/json" type for the purpose of displaying in web
browsers.
Additional information:
Magic number(s):
File extension(s): .scim .scm
Macintosh file type code(s):
Person & email address to contact for further information: SCIM
mailing list "<scim@ietf.org>"
Intended usage: COMMON* (see restrictions)
Restrictions on usage: For most client types, it is sufficient to
recognize the content as equivalent to "application/json".
Applications intending to use the SCIM protocol SHOULD use the
"application/scim+json" media type.
Author: Phil Hunt
Change controller: IETF
8.2. Registering URIs for SCIM Messages π¦
Per the "SCIM Schema URIs for Data Resources" registry set up by [RFC7643], this part defines and registers the SCIM protocol request/response JSON schema URN identifier prefix of "urn:ietf:params:scim:api:messages:2.0". It's part of the URN sub-namespace for SCIM, and there's no specific associated resource type πΈ.
+---------------------------------+-----------------+---------------+
| Schema URI | Name | Reference |
+---------------------------------+-----------------+---------------+
| urn:ietf:params:scim:api: | List/Query | See Section |
| messages:2.0:ListResponse | Response | 3.4.2 |
| | | |
| urn:ietf:params:scim:api: | POST Query | See Section |
| messages:2.0:SearchRequest | Request | 3.4.3 |
| | | |
| urn:ietf:params:scim:api: | PATCH Operation | See Section |
| messages:2.0:PatchOp | | 3.5.2 |
| | | |
| urn:ietf:params:scim:api: | Bulk Operations | See Section |
| messages:2.0:BulkRequest | Request | 3.7 |
| | | |
| urn:ietf:params:scim:api: | Bulk Operations | See Section |
| messages:2.0:BulkResponse | Response | 3.7 |
| | | |
| urn:ietf:params:scim:api: | Error Response | See Section |
| messages:2.0:Error | | 3.12 |
+---------------------------------+-----------------+---------------+
Table 10: SCIM Schema URIs for Data Resources
9. References π
The reference list is up next, bestie π
9.1. Normative References π
okay so these are the docs you need to have read before this spec makes any sense πβ¨ bestie, I'm not kidding. Here they are:
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<http://www.rfc-editor.org/info/rfc2119>.
[RFC3629] Yergeau, F., "UTF-8, a transformation format of
ISO 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629,
November 2003, <http://www.rfc-editor.org/info/rfc3629>.
[RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
Resource Identifier (URI): Generic Syntax", STD 66,
RFC 3986, DOI 10.17487/RFC3986, January 2005,
<http://www.rfc-editor.org/info/rfc3986>.
[RFC5234] Crocker, D., Ed., and P. Overell, "Augmented BNF for
Syntax Specifications: ABNF", STD 68, RFC 5234,
DOI 10.17487/RFC5234, January 2008,
<http://www.rfc-editor.org/info/rfc5234>.
[RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
(TLS) Protocol Version 1.2", RFC 5246,
DOI 10.17487/RFC5246, August 2008,
<http://www.rfc-editor.org/info/rfc5246>.
[RFC5789] Dusseault, L. and J. Snell, "PATCH Method for HTTP",
RFC 5789, DOI 10.17487/RFC5789, March 2010,
<http://www.rfc-editor.org/info/rfc5789>.
[RFC6125] Saint-Andre, P. and J. Hodges, "Representation and
Verification of Domain-Based Application Service Identity
within Internet Public Key Infrastructure Using X.509
(PKIX) Certificates in the Context of Transport Layer
Security (TLS)", RFC 6125, DOI 10.17487/RFC6125,
March 2011, <http://www.rfc-editor.org/info/rfc6125>.
[RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework",
RFC 6749, DOI 10.17487/RFC6749, October 2012,
<http://www.rfc-editor.org/info/rfc6749>.
[RFC6750] Jones, M. and D. Hardt, "The OAuth 2.0 Authorization
Framework: Bearer Token Usage", RFC 6750,
DOI 10.17487/RFC6750, October 2012,
<http://www.rfc-editor.org/info/rfc6750>.
[RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
Interchange Format", RFC 7159, DOI 10.17487/RFC7159,
March 2014, <http://www.rfc-editor.org/info/rfc7159>.
[RFC7230] Fielding, R., Ed., and J. Reschke, Ed., "Hypertext
Transfer Protocol (HTTP/1.1): Message Syntax and Routing",
RFC 7230, DOI 10.17487/RFC7230, June 2014,
<http://www.rfc-editor.org/info/rfc7230>.
[RFC7231] Fielding, R., Ed., and J. Reschke, Ed., "Hypertext
Transfer Protocol (HTTP/1.1): Semantics and Content",
RFC 7231, DOI 10.17487/RFC7231, June 2014,
<http://www.rfc-editor.org/info/rfc7231>.
[RFC7232] Fielding, R., Ed., and J. Reschke, Ed., "Hypertext
Transfer Protocol (HTTP/1.1): Conditional Requests",
RFC 7232, DOI 10.17487/RFC7232, June 2014,
<http://www.rfc-editor.org/info/rfc7232>.
[RFC7235] Fielding, R., Ed., and J. Reschke, Ed., "Hypertext
Transfer Protocol (HTTP/1.1): Authentication", RFC 7235,
DOI 10.17487/RFC7235, June 2014,
<http://www.rfc-editor.org/info/rfc7235>.
[RFC7538] Reschke, J., "The Hypertext Transfer Protocol Status
Code 308 (Permanent Redirect)", RFC 7538,
DOI 10.17487/RFC7538, April 2015,
<http://www.rfc-editor.org/info/rfc7538>.
[RFC7613] Saint-Andre, P. and A. Melnikov, "Preparation,
Enforcement, and Comparison of Internationalized Strings
Representing Usernames and Passwords", RFC 7613,
DOI 10.17487/RFC7613, August 2015,
<http://www.rfc-editor.org/info/rfc7613>.
[RFC7643] Hunt, P., Ed., Grizzle, K., Wahlstroem, E., and
C. Mortimore, "System for Cross-domain Identity
Management: Core Schema", RFC 7643, DOI 10.17487/RFC7643,
September 2015, <http://www.rfc-editor.org/info/rfc7643>.
9.2. Informative References πΈ
these ones aren't strictly required reading, but they're super good for context, so go poke around if you're curious π§
[HTTP-BASIC-AUTH]
Reschke, J., "The 'Basic' HTTP Authentication Scheme",
Work in Progress, draft-ietf-httpauth-basicauth-update-07,
February 2015.
[OAuth-PoP-Arch]
Hunt, P., Ed., Richer, J., Mills, W., Mishra, P., and H.
Tschofenig, "OAuth 2.0 Proof-of-Possession (PoP) Security
Architecture", Work in Progress,
draft-ietf-oauth-pop-architecture-02, July 2015.
[OpenSearch]
Clinton, D., "OpenSearch Protocol 1.1, Draft 5",
December 2005, <http://www.opensearch.org/Specifications/
OpenSearch/1.1>.
[RFC6265] Barth, A., "HTTP State Management Mechanism", RFC 6265,
DOI 10.17487/RFC6265, April 2011,
<http://www.rfc-editor.org/info/rfc6265>.
[RFC6819] Lodderstedt, T., Ed., McGloin, M., and P. Hunt, "OAuth 2.0
Threat Model and Security Considerations", RFC 6819,
DOI 10.17487/RFC6819, January 2013,
<http://www.rfc-editor.org/info/rfc6819>.
[RFC6902] Bryan, P., Ed., and M. Nottingham, Ed., "JavaScript Object
Notation (JSON) Patch", RFC 6902, DOI 10.17487/RFC6902,
April 2013, <http://www.rfc-editor.org/info/rfc6902>.
[RFC7486] Farrell, S., Hoffman, P., and M. Thomas, "HTTP Origin-
Bound Authentication (HOBA)", RFC 7486,
DOI 10.17487/RFC7486, March 2015,
<http://www.rfc-editor.org/info/rfc7486>.
[RFC7521] Campbell, B., Mortimore, C., Jones, M., and Y. Goland,
"Assertion Framework for OAuth 2.0 Client Authentication
and Authorization Grants", RFC 7521, DOI 10.17487/RFC7521,
May 2015, <http://www.rfc-editor.org/info/rfc7521>.
[RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre,
"Recommendations for Secure Use of Transport Layer
Security (TLS) and Datagram Transport Layer Security
(DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525,
May 2015, <http://www.rfc-editor.org/info/rfc7525>.
[RFC7564] Saint-Andre, P. and M. Blanchet, "PRECIS Framework:
Preparation, Enforcement, and Comparison of
Internationalized Strings in Application Protocols",
RFC 7564, DOI 10.17487/RFC7564, May 2015,
<http://www.rfc-editor.org/info/rfc7564>.
[XML-Schema]
Biron, P. and A. Malhotra, "XML Schema Part 2: Datatypes
Second Edition", W3C Recommendation, October 2004,
<http://www.w3.org/TR/xmlschema-2/>.
Acknowledgements π«Ά
the editor wants to give a huge shoutout to the editors of the earlier draft versions of this doc, who did the groundwork:
- Trey Drake, UnboundID
- Chuck Mortimore, Salesforce
the editor also says thank you to everyone in the SCIM working group for backing this spec π
Contributors π
these lovely people also contributed:
- Samuel Erdtman (samuel@erdtman.se)
- Patrick Harding (pharding@pingidentity.com)
Authors' Addresses β¨
here's where to find the authors:
Phil Hunt (editor)
Oracle Corporation
Email: phil.hunt@yahoo.com
Kelly Grizzle
SailPoint
Email: kelly.grizzle@sailpoint.com
Morteza Ansari
Cisco
Email: morteza.ansari@cisco.com
Erik Wahlstroem
Nexus Technology
Email: erik.wahlstrom@nexusgroup.com
Chuck Mortimore
Salesforce.com
Email: cmortimore@salesforce.com
π¦ where this page comes from
- ietf: rfc7644 2015-09
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms