Skip to main content

Overview

SCIM filter strings tell list endpoints which resources to return. The theAuth parser implements the complete grammar from RFC 7644 §3.4.2.2. Any filter string that does not conform to that grammar returns 400 invalidFilter before the database is touched.

Grammar

The grammar below is taken directly from RFC 7644 §3.4.2.2.

Productions in plain English

  • attrExp is the basic building block: an attribute, an operator, and a value. Example: userName eq "bjensen".
  • valuePath wraps a multi-valued attribute with square brackets. Example: emails[type eq "work"].
  • logExp chains two filters with and or or. Precedence is handled by the parser, not you.
  • not(…) negates whatever is inside the parentheses.
  • attrPath can be a simple name (userName), a dotted path (name.givenName), or URN-prefixed (urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department).

Comparison operators

All string comparisons are case-insensitive per RFC 7644 §3.4.2.2. "BJensen" and "bjensen" are the same value.

eq

Returns true when the attribute value equals the comparison value exactly (after case-folding for strings).
Matches:

ne

The inverse of eq. Returns true when the attribute value does not equal the comparison value.
Matches any user whose userType is not Admin.

co

Returns true when the attribute value contains the comparison value as a substring.
Matches Jensen, Jensens, jenson. Does not match jen.

sw

Returns true when the attribute value starts with the comparison value.
Matches bjensen, bjoern. Does not match barbara.

ew

Returns true when the attribute value ends with the comparison value.
Matches bjensen@example.com. Does not match bjensen@example.org.

gt

Returns true when the attribute value is greater than the comparison value. For strings, comparison is lexicographic. ISO 8601 timestamps (2024-06-01T00:00:00Z) are lexicographically ordered, so gt and lt work correctly on meta.lastModified without any special date parsing.
Matches users modified after 2025-01-01.

ge

Returns true when the attribute value is greater than or equal to the comparison value. Same rules as gt.

lt

Returns true when the attribute value is less than the comparison value.

le

Returns true when the attribute value is less than or equal to the comparison value.

Presence operator

pr tests whether an attribute is present and non-empty. It takes no comparison value.
Returns users that have at least one email address. An empty array, null, or a missing key all fail pr.
Returns only users with a non-empty nickName. Users without the attribute are excluded.

Logical combinators

and

Both clauses must match.

or

At least one clause must match.

not

Negates the enclosed filter. The parentheses are required.

Precedence

The parser follows standard logic precedence: not binds tightest, then and, then or. This means:
is parsed as:
If that is not what you want, use parentheses:
The second form requires c eq "3" to be true for any result to be returned.

Value-path selectors

A value-path selector applies a filter to the elements of a multi-valued attribute. The expression is true when at least one element satisfies the inner filter.
This matches a user who has at least one email object where type is "work". It does not require the work email to be the primary address or the only address. Combinators work inside the brackets:
This matches a user whose work email also ends with @example.com. Both conditions must hold on the same array element, not across different elements. Nested value paths are not supported. emails[addresses[...]] returns 400 invalidFilter.

Attribute paths

Dot notation

Use a dot to navigate into a sub-attribute:

URN-qualified paths

Schema extensions use a URN prefix followed by the attribute name, separated by a colon:
The parser splits on the last : when the path starts with urn:, then reads the attribute from the extension object keyed by the URN in the resource.
Dot notation inside a URN path is also valid:

Data types in comparisons

Strings support JSON-style escape sequences inside quotes: \", \\, \/, \t, \n, \r. Ordering operators (gt, ge, lt, le) on booleans and null always return false. Ordering on a number against a string also returns false.

Error responses

When the filter string is malformed, the server returns:
The detail field contains the position in the original filter string where the parser stopped. Common causes:

Security notes

The parser builds a finite AST and walks it. No eval, no regex matching against untrusted input. Filter complexity grows linearly with input length. The recursive descent parser does not recurse in a way that is proportional to nesting depth beyond what the input length permits, so deeply nested parentheses do not cause a stack overflow. Very long input strings are rejected at the HTTP transport layer before the parser runs.

Practical examples

Last modified on October 7, 2026