<?xml version="1.0" encoding="utf-8"?>

<?xml-model href="rfc7991bis.rnc"?>  

<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>

<rfc xmlns:xi="http://www.w3.org/2001/XInclude" category="info"
  docName="draft-peterson-scim-cursor-pagination-01" ipr="trust200902" obsoletes=""
  updates="7643,7644" submissionType="IETF" xml:lang="en" version="3">

  <front>

    <title abbrev="SCIM Cursor Pagination">Cursor-based Pagination of SCIM Resources</title>

    <author fullname="Matt Peterson" initials="M" surname="Peterson">
      <organization>One Identity</organization>
      <address>
        <email>matt.peterson@oneidentity.com</email>
      </address>
    </author>

    <author fullname="Danny Zollner" initials="D" surname="Zollner">
      <organization>Microsoft</organization>
      <address>
        <email>danny.zollner@microsoft.com</email>
      </address>
    </author>

    <date year="2022" month="9" day="28"/>

    <!-- Meta-data Declarations -->

    <area>General</area>

    <workgroup>SCIM</workgroup>

    <keyword>SCIM</keyword>
    <keyword>pagination</keyword>
    <keyword>cursor</keyword>

    <abstract>
      <t> This document defines additional SCIM query parameters and result attributes to allow use
        of cursor-based pagination in SCIM implementations that are implemented with existing
        code bases, databases, or APIs where cursor-based pagination is already well-established.
      </t>
    </abstract>
  </front>

  <middle>
    <section title="Introduction">
      <t> The two common patterns for result pagination in HTTP-based protocols are index-based
        pagination and cursor-based pagination. Rather than attempt to compare and contrast the
        advantages and disadvantages of competing pagination patterns, this document simply
        recognizes that SCIM service providers are commonly implemented as an interoperability
        layer on top of already existing application codebases, databases, and/or APIs that already
        have a well-established pagination pattern. </t>

      <t> Translating from an underlying cursor-based pagination pattern to the index-based
        pagination defined in <xref target="RFC7644" sectionFormat="of" section="3.4.2.4"/>
        ultimately requires the SCIM service provider to fully iterate the underlying cursor, store
        the results, and then serve indexed pages from the stored results. This task of "pagination
        translation" dramatically increases complexity and memory requirements for implementing a
        SCIM Service Provider, and may be an impediment to SCIM adoption for some applications and
        identity systems. </t>

      <t> This document defines a simple addition to the SCIM protocol that allows SCIM service
        providers to reuse underlying cursors without expensive translation. Support for
        cursor-based pagination in SCIM encourages broader cross-application identity management
        interoperability by encouraging SCIM service provider implementations for applications and
        identity systems where cursor-based pagination is already well-established.</t>

      <section title="Notational Conventions">
        <t>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 <xref target="RFC2119"/>. </t>
      </section>
    </section>

    <section title="Query Parameters and Response Attributes" anchor="query_params">
      <t>The following table describes the URL pagination parameters requests for using cursor-based
        pagination: </t>

      <table>
        <thead>
          <tr>
            <th>Parameter</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">cursor</td>
            <td align="left"> The string value of the nextCursor attribute from a previous result
              page. The cursor value MUST be empty or omitted for the first request of a
              cursor-paginated query. </td>
          </tr>
          <tr>
            <td align="left">count</td>
            <td align="left"> A positive integer. Specifies the desired maximum number of query
              results per page, e.g., count=10. When specified, the service provider MUST NOT return
              more results than specified, although it MAY return fewer results. If count is not
              specified in the query, the maximum number of results is set by the service provider.
            </td>
          </tr>
        </tbody>
      </table>

      <t> The following table describes cursor-based pagination attributes returned in a paged query
        response: </t>

      <table>
        <thead>
          <tr>
            <th>Element</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td align="left">nextCursor</td>
            <td align="left"> A cursor value string that MAY be used in a subsequent request to
              obtain the next page of results. Service providers supporting cursor-based pagination
              MUST include nextCursor in all paged query responses except when returning the last
              page. nextCursor is omitted from a response only to indicate that there are no more
              result pages. </td>
          </tr>
          <tr>
            <td align="left">previousCursor</td>
            <td align="left"> A cursor value string that MAY be used in a subsequent request to
              obtain the previous page of results. Use of previousCursor is OPTIONAL. Service
              Providers that are unable to support a previousCursor MAY omit previousCursor when
              sending paged query responses. </td>
          </tr>
        </tbody>
      </table>

      <t> For example, to retrieve the first 10 Users, use an empty cursor and set the count to 10: </t>

      <sourcecode>
        <![CDATA[
  GET /Users?cursor&count=10
  Host: example.com
  Accept: application/scim+json
  Authorization: Bearer U8YJcYYRMjbGeepD
]]>
      </sourcecode>

      <t> The response to the query above returns metadata regarding pagination similar to the
        following example (actual resources removed for brevity): </t>

      <sourcecode>
        <![CDATA[
  {
    "totalResults":100,
    "itemsPerPage":10,
    "nextCursor":"VZUTiyhEQJ94IR",
    "schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
    "Rsesources":[{
       ...
     }]
  }
]]>
      </sourcecode>

      <t> Given the example above, to continue pagination, set the cursor to the value of nextCursor
        ("VZUTiyhEQJ94IR") and re-fetch: </t>

      <sourcecode>
        <![CDATA[
  GET /Users?cursor=VZUTiyhEQJ94I&count=10
  Host: example.com
  Accept: application/scim+json
  Authorization: Bearer U8YJcYYRMjbGeepD
]]>
      </sourcecode>

      <t> If a Service Provider encounters an invalid cursor or count value (or other error
        condition), the Service Provider SHOULD return appropriate HTTP response status code and
        JSON detail error response as defined in <xref target="RFC7644" sectionFormat="of"
          section="3.1.2"/>. </t>

      <section title="Cursors as the Only Pagination Method">
        
        <t>A SCIM Service Provider MAY require cursor-based pagination to retrieve all results
          for a query by including a "nextCursor" value in the response even when the original
          query does not include the "cursor" parameter.</t>
        
        <t>For example: </t>
        
        <sourcecode>
          <![CDATA[
   GET /Users
   Host: example.com
   Accept: application/scim+json
]]>
        </sourcecode>
        
        <t> The SCIM Service Provider may responded to the above query with a single page
          of results and a "nextCursor" value as shown in the below example (Resources omitted 
          for brevity):</t>
        
        <sourcecode>
          <![CDATA[
  {
    "totalResults":5000,
    "itemsPerPage":100,
    "nextCursor":"HPq72Pax3JUaNa",
    "schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
    "Resources":[{
       ...
     }]
  }
]]>
        </sourcecode>
        
      </section>
      
    </section>

    <section title="Querying Resources Using HTTP POST">
      <t><xref target="RFC7644" sectionFormat="of" section="3.4.2.4"/> defines how clients MAY
        execute the HTTP POST verb combined with the "/.search" path extension to issue execute
        queries without passing parameters on the URL. When using "./search", the client would pass
        the parameters defined in <xref target="query_params"/>
      </t>

      <sourcecode>
        <![CDATA[
  POST /User.search
  Host: example.com
  Accept: application/scim+json
  Authorization: Bearer U8YJcYYRMjbGeepD
  {
    "schemas": [
      "urn:ietf:params:scim:api:messages:2.0:SearchRequest"],
    "attributes": ["displayName", "userName"],
    "filter":
       "displayName sw \"smith\"",
    "cursor": "",
    "count": 10
  }
]]>
      </sourcecode>

      <t>Which would return a result containing a "nextCursor" value which may be used by the client
        in a subsequent call to return the next page of resources</t>

      <sourcecode>
        <![CDATA[
  {
    "totalResults":100,
    "itemsPerPage":10,
    "nextCursor":"VZUTiyhEQJ94IR",
    "schemas":["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
    "Resources":[{
       ...
     }]
  }
]]>
      </sourcecode>
      
    </section>

    <section title="Service Provider Configuration">

      <t> The /ServiceProviderConfig resource defined in <xref target="RFC7644" sectionFormat="of"
          section="4"/> facilitates discovery of SCIM service provider features. A SCIM Service
        provider implementing cursor-based pagination SHOULD include the following additional
        attribute in JSON document returned by the /ServiceProviderConfig endpoint: </t>

      <dl>
        <dt>pagination</dt>
        <dd> A complex type that indicates pagination configuration options. OPTIONAL. </dd>
        <dt/>
        <dd>
          <dl>
            <dt>cursor</dt>
            <dd> A Boolean value specifying support of cursor-based paginations. REQUIRED. </dd>
          </dl>
          <dl>
            <dt>index</dt>
            <dd> A Boolean value specifying support of index-based pagination. REQUIRED. </dd>
          </dl>
        </dd>
      </dl>

      <t> Before using cursor-based pagination, a SCIM client MAY fetch the Service Provider
        Configuration document from the SCIM service provider and verify that cursor-based
        pagination is supported. </t>

      <t> For example: </t>
      <sourcecode>
        <![CDATA[
   GET /ServiceProviderConfig
   Host: example.com
   Accept: application/scim+json
]]>
      </sourcecode>

      <t> A service provider supporting both cursor-based pagination and index-based pagination
        would return a document similar to the following (full ServiceProviderConfig schema
        defined in <xref target="RFC7643" sectionFormat="of" section="5"/> has been omitted
        for brevity): </t>
      <sourcecode>
        <![CDATA[
  {
    "schemas": [
      "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
      
      ... 

    "pagination": {
       "cursor": true,
       "index": true
    },

    ...
      
   }
]]>
      </sourcecode>

    </section>

  </middle>

  <back>

    <references title="Normative References">
      <xi:include href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.2119.xml"/>
      <xi:include href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.7643.xml"/>
      <xi:include href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.7644.xml"/>
    </references>

  </back>

</rfc>
