---
# System prepended metadata

title: AuthZEN pagination
tags: [api, design]

---

# AuthZEN pagination discussion

## Context

The AuthZEN search APIs currently define a pagination pattern since there may be a significant number of results returned by these APIs.

The current spec uses the "cursor" pattern for pagination: the PDP implementation returns an OPTIONAL `page` JSON object which includes a `next_token` key with an opaque value. The caller can structure a subsequent request that includes a `page.next_token` key with the value returned by the PDP in order to retrieve the next page of results.

## Problem statement

It's been suggested that supporting the "offset/length" pattern in place of, or in addition to, the "cursor" pattern would be advantageous. This is because some PDPs support (or at least prefer) this style.

Barring that, it's been suggested that removing the spec's details for pagination would make it more palateable for PDPs that prefer the offset/length pattern.

## Options

1. Continue to support only cursor-based pagination
2. Switch to offset-based pagination
3. Support both styles
4. Support neither style (leave unspecified)

## Advantages of each style

Offset/length pagination style exposes the pagination semantics to the client. Specifically, a client can send a numerical `offset` to the service, which instructs the service to retrieve `length` results from that offset. This is conducive for UI design that shows N results per page, and allows a user to skip to the Nth page of a result set.

Cursor-based pagination does not expose the pagination semantics to the client. Specifically, a service returns an opaque token to the client, which the client can echo back in a subsequent request to retrieve the next page of data. A client can store the page tokens that it receives, and thereby support a "next-page" / "previous-page" UI semantic.

In this way, the offset/length pagination style supports a use-case that cursor-based pagination does not.

However, the cursor-based pagination style has become the dominant pattern for pagination for common developer APIs, and even with previous versions of APIs that support offset/length, that support is often considered "legacy". The following APIs all support cursor-based pagination:
* Cloud
  * Google Cloud, Drive, YouTube, Maps, Ads, etc
  * Microsoft Azure, Graph/O365
  * AWS
* Source control: GitHub (graph), GitLab
* IAM: Okta, MS Entra, AWS Cognito, Google Cloud Identity, Stytch, ...
* Social: Twitter, FB graph, Reddit
* CRM: Salesforce, Hubspot
* File sharing: Dropbox, Box
* Support: Zendesk, Intercom
* Productivity: AirTable, Notion
* DevTools: DataDog, Sentry
* DevOps: Kubernetes
* Other popular dev APIs: Slack, Stripe, Shopify, Zoom, OpenAI

## Tradeoffs 

### Cursor-only

Pro:
- more generic than offset-based pagination (any offset-based pagination system can return an "opaque" cursor value that encodes offset&length)
- most prevalent pagination style on the web today
- supporting one style reduces PEP complexity

Con:
- does not support jumping to Nth page of results

### Offset-only

Pro:
- supports jumping to Nth page of results
- supporting one style reduces PEP complexity

Con:
- cursor-based PDPs cannot easily implement offset/length based pagination (this is, in my opinion, a fatal con)
- considered the "legacy" style of pagination

### Both

Pro:
- makes it easy for PDPs of each style to implement pagination with the least burden on the PDP builder

Con: 
- more implementation burden on a PEP that wants to work generically across PDP implementations. Specifically, a PEP would need to interrogate the PDP for which pagination style it supports (via a metadata request), and then make the appropriate style pagination call.

### Neither

Con:
- You cannot write generic PEPs that retrieve more than one page of results (this is, in my opinion, a fatal con)

## Analysis

My recommendation is (1) - keep cursor-only pagination.

Option 2 is pretty much a non-starter for PDPs that under the covers implement cursor-based pagination, whereas option 1 can be supported by offset/length based systems.

Option 3 adds too much complexity to the API from a PEP implementor perspective relative to the benefit. It's pretty trivial for offset/length based PDPs to support the cursor style, and I believe it's very suboptimal to offload that complexity to the PEP writer, increasing the barriers to adoption.

Outside of this, the only reason a caller would choose offset/length over cursor-based implementations would be to enable implementing UI that allows users to jump into a page of results. But if some portion of the PDPs don't implement this style, this type of UI would not be feasible to support anyway!

Option 4 is the least compelling one, since it kneecaps the API, making it only useful for demo scenarios and not for real-world scenarios where a large set of results may be returned.

### Variation

If we agree that Option 1 makes most sense but still want to enable offset/length based implementations to expose those "advanced" semantics to a caller that is motivated enough to offer that UI style in an "adaptive fashion", we could do the following:
1. Make cursor-based pagination MANDATORY
2. Make offset/length pagination DISCOVERABLE and OPTIONAL

A PEP that only needs the capability to page through results using next (and potentially previous) semantics can rely on (1).

A PEP that wants to adapt its UI for "jumping into a result page" if the capability is available can invest in the extra complexity of interrogating the PDP and using the offset/length capability if its available.
