Filters
IdentityScribe supports four filter formats for queries. Filters are auto-detected, so you can use whichever format fits your use case.
Format detection
Section titled “Format detection”Filters are detected in this order:
| Format | Detection | Best For |
|---|---|---|
| JSON | Starts with { or [ | Programmatic queries, SDKs |
| LDAP | Starts with ( and ends with ) | Legacy systems, LDAP clients |
| FleX | Tried next | Interactive queries, config files |
| SCIM | Fallback | REST APIs, SCIM clients |
Quick comparison
Section titled “Quick comparison”| Operation | FleX | JSON | SCIM | LDAP |
|---|---|---|---|---|
| Equality | cn = John | {"cn": "John"} | cn eq "John" | (cn=John) |
| Not equal | cn != John | {"cn": {"ne": "John"}} | cn ne "John" | (!(cn=John)) |
| Starts with | cn ^= J | {"cn": {"sw": "J"}} | cn sw "J" | (cn=J*) |
| Contains | cn %= oh | {"cn": {"co": "oh"}} | cn co "oh" | (cn=*oh*) |
| Exists | cn? | {"cn": {"pr": true}} | cn pr | (cn=*) |
| AND | a=1 b=2 | {"a": "1", "b": "2"} | a eq "1" and b eq "2" | (&(a=1)(b=2)) |
| OR | a=1 or b=2 | {"_or_": [...]} | a eq "1" or b eq "2" | (|(a=1)(b=2)) |
| Attr group | a|b = x | {"a|b": "x"} | — | — |
Temporal references
Section titled “Temporal references”When filtering on timestamp attributes (createTimestamp, modifyTimestamp, verifiedTimestamp), you can use flexible temporal references instead of absolute timestamps. This feature works with all filter formats (FleX, JSON, SCIM, LDAP).
| Format | Example | Description |
|---|---|---|
now | modifyTimestamp ge now | Current time |
now-duration | modifyTimestamp ge now-1h | 1 hour ago |
now+duration | verifiedTimestamp lt now+1d | 1 day from now |
| Duration | createTimestamp ge 7d | 7 days ago |
| ISO duration | modifyTimestamp ge P30D | 30 days ago |
| Partial date | createTimestamp ge 2024 | Start of 2024 |
| Day keywords | modifyTimestamp ge today | Midnight UTC |
| Period keywords | createTimestamp ge this_week | Start of period |
| Relative periods | modifyTimestamp ge last 3 days | N units ago |
Day keywords: yesterday, today, tomorrow
Period keywords: this week, last week, this month, last month, this year, last year
(Also: this_week, thisweek, last-month, etc.)
Relative periods: last N units where units can be days, hours, minutes, weeks, etc.
Examples
Section titled “Examples”# FleXmodifyTimestamp ge todaycreateTimestamp ge last 3 days
# SCIMmodifyTimestamp ge "today"createTimestamp ge "last 3 days"
# LDAP(modifyTimestamp>=today)(createTimestamp>=last 3 days)
# JSON{"modifyTimestamp": {"ge": "today"}}{"createTimestamp": {"ge": "last 3 days"}}See Temporal references for the complete list of supported formats.
FleX is a flexible, human-readable query language. The name: Flexible Filter Expressions. Whitespace is lenient, and natural language operators make filters self-documenting.
Primary use case: Runtime query parsing for REST/GraphQL filter parameters, interactive search, and monitoring rules.
Secondary benefit: Cleaner syntax for HOCON configuration files compared to LDAP/SCIM/JSON formats.
Quick start
Section titled “Quick start”# Simple equalitystatus = activestatus is active
# Multiple conditions (implicit AND)result=ok duration<=50ms
# OR conditionsresult=ok or result=warnresult=ok, result=warn
# Natural languageduration is at most 100msname starts with JohnOperators
Section titled “Operators”Comparison
Section titled “Comparison”| Operator | Aliases | Description |
|---|---|---|
=, == | eq, is, equals | Equality |
!=, !== | ne, isnt, is not | Not equal |
> | gt, after, greater than | Greater than |
>= | ge, min, at least | Greater or equal |
< | lt, before, less than | Less than |
<= | le, max, at most | Less or equal |
String matching
Section titled “String matching”| Operator | Aliases | Description |
|---|---|---|
^= | sw, starts with, prefix | Starts with |
$= | ew, ends with, suffix | Ends with |
%= | co, contains, has | Contains substring |
*= | matches, like, glob | Wildcard/glob pattern |
~= | approx, sounds like | Approximate match (phonetic) |
Presence
Section titled “Presence”| Operator | Aliases | Description |
|---|---|---|
? | exists, present, pr | Attribute exists |
Set membership
Section titled “Set membership”| Operator | Aliases | Description |
|---|---|---|
in | one of | Value in set |
not in | !in, not one of | Value not in set |
Combinators
Section titled “Combinators”AND (Implicit)
Section titled “AND (Implicit)”Whitespace between conditions implies AND:
result=ok duration<=50msresult=ok and duration<=50msresult=ok & duration<=50msresult=ok && duration<=50msOR (explicit)
Section titled “OR (explicit)”Use or, ,, |, or ||:
result=ok or result=warnresult=ok, result=warnresult=ok | result=warnresult=ok || result=warnPrecedence
Section titled “Precedence”AND binds tighter than OR. Use parentheses to override:
# Parses as: (channel=LDAP AND op=Search) OR (channel=REST AND op=Search)channel=LDAP op=Search or channel=REST op=Search
# Use parentheses to overridechannel=LDAP (op=Search or op=Bind)Lenient parsing
Section titled “Lenient parsing”FleX uses forgiving whitespace handling:
# These are all equivalentage != 5age ! = 5 # space after ! is OKage !eq 5 # attached to word operatorage ! eq 5 # space after ! is OK
# Natural language prefixesage is greater than 5age is not greater than 5 # negated with "is not"age isn't greater than 5 # contraction formage isnt greater than 5 # without apostrophe
# "not" prefix works with all operatorsname not contains foopath not starts with /tmpemail not existsNegation
Section titled “Negation”Negate operators with ! or not:
result != okresult !eq okresult not eq okcn !starts with 'Test'cn not starts with 'Test'email !existsemail not existsNegate entire expressions with ! or not():
!(result = ok)not(result = ok)Values
Section titled “Values”Unquoted values
Section titled “Unquoted values”Simple values without spaces or special characters:
status = activepriority = 42enabled = trueduration <= 50msQuoted values
Section titled “Quoted values”Use backticks (preferred), single quotes, or double quotes for values with spaces:
cn = `John Doe`cn = 'John Doe'cn = "John Doe"Special values
Section titled “Special values”value = null # Treated as "not exists"value = nil # Same as nullvalue = true # Booleanvalue = false # BooleanTo match the literal string “null”, quote it:
value = `null` # Matches the string "null"Supported value formats
Section titled “Supported value formats”FleX recognizes these unquoted value formats:
- Numbers:
42,3.14,1_000_000,1.5e-3 - Hex/octal/binary:
0xFF,0o755,0b1010 - Durations:
50ms,5s,1m,2h,1d,PT1M30S - Timestamps:
2024-01-15,2024-01-15T10:30:00Z - UUIDs:
550e8400-e29b-41d4-a716-446655440000 - IPs:
192.168.1.1,::1 - Emails:
user@example.com
Attribute groups
Section titled “Attribute groups”Apply the same condition to multiple attributes:
# Pipe syntax (no whitespace)sn|givenName|name contains 'admin'
# Brace syntax (whitespace allowed){sn, givenName, name} contains 'admin'
# Both expand to:sn contains 'admin' or givenName contains 'admin' or name contains 'admin'Set membership
Section titled “Set membership”Use in with parentheses or brackets:
status in (active, pending, review)status in [active, pending, review]role not in (admin, superuser)Empty sets check presence:
status in () # Same as: status existsstatus not in () # Same as: status not existsLDAP extensible match
Section titled “LDAP extensible match”For DN-based matching (LDAP :dn modifier):
member:dn := "cn=John,ou=users,dc=example,dc=com"ou:dn := EngineeringConfig examples
Section titled “Config examples”Monitoring rules
Section titled “Monitoring rules”monitoring { rules = [ { action = exclude, where = "scribe.result=ok duration.seconds<=50ms" } { action = exclude, name = "Hints.*", where = "duration.seconds is at most 100ms" } { action = include, where = "scribe.result != ok, duration.seconds >= 5s" } ]}LDAP filters
Section titled “LDAP filters”transcribes { ldap { filter = "objectClass=Person employeeStatus!=terminated" filter = "objectClass=Person (employeeType=FTE or employeeType=Contractor)" }}JSON filters provide a structured, programmatic way to build queries. Ideal for SDKs, code generation, and type-safe query building.
Quick start
Section titled “Quick start”// Simple equality{"cn": "john"}
// Multiple conditions (AND){"cn": "john", "sn": "doe"}
// Array of values (OR){"cn": ["john", "jane"]}
// Operator with value{"cn": {"sw": "A"}}
// Explicit logical operators{"_or_": [{"cn": "a"}, {"cn": "b"}]}{"_not_": {"disabled": "true"}}Root structure
Section titled “Root structure”JSON filters can have two root types:
- Object
{...}: Keys are combined with AND - Array
[...]: Elements are combined with AND
// Object root - all conditions ANDed{"cn": "john", "sn": "doe", "active": "true"}
// Array root - all elements ANDed[{"cn": "john"}, {"sn": "doe"}]Operators
Section titled “Operators”| Operator | Aliases | Meaning |
|---|---|---|
eq | equals, is, = | Equals |
ne | notEquals, != | Not equals |
co | contains, % | Contains substring |
sw | startsWith, ^ | Starts with |
ew | endsWith, $ | Ends with |
pr | exists | Attribute present |
gt | >, after | Greater than |
ge | gte, >=, min | Greater or equal |
lt | <, before | Less than |
le | lte, <=, max | Less or equal |
approx | ~, soundsLike | Approximate match |
matches | * | Wildcard pattern |
includes | in, oneOf | Value in set |
excludes | notIn, notOneOf | Value not in set |
Logical operators
Section titled “Logical operators”Use _and_, _or_, and _not_ (or without underscores) for explicit logic:
// OR - any condition matches{"_or_": [{"status": "active"}, {"status": "pending"}]}
// AND - all conditions match (explicit){"_and_": [{"role": "admin"}, {"active": "true"}]}
// NOT - negate condition{"_not_": {"disabled": "true"}}
// Nested logic{"_and_": [ {"type": "user"}, {"_or_": [{"role": "admin"}, {"role": "operator"}]}]}Value coercion
Section titled “Value coercion”JSON values are coerced to strings:
| JSON Type | Result |
|---|---|
| String | Used as-is |
| Number | Plain string (no scientific notation) |
| Boolean | "true" or "false" |
| Null | Treated as “not exists” |
{"age": 25} // age = "25"{"active": true} // active = "true"{"deleted": null} // deleted not existsAttribute groups
Section titled “Attribute groups”Apply the same condition to multiple attributes using pipe syntax:
// Search across multiple name fields{"sn|givenName|cn": {"co": "admin"}}
// Equivalent to:{"_or_": [ {"sn": {"co": "admin"}}, {"givenName": {"co": "admin"}}, {"cn": {"co": "admin"}}]}Advanced examples
Section titled “Advanced examples”// Complex query with mixed operators{ "objectClass": "user", "cn": {"sw": "A"}, "department": ["Engineering", "Product"], "_not_": {"status": "terminated"}}
// Array operator (IN){"status": {"in": ["active", "pending", "review"]}}
// Multiple operators on same attribute{"age": {"ge": "18", "lt": "65"}}SCIM 2.0 filter syntax (RFC 7644) for REST-native queries. Basic SCIM filters work in FleX mode, though advanced features like complex value filters (emails[type eq "work"]), dotted paths, and URN-qualified attributes are not supported.
Quick start
Section titled “Quick start”cn eq "john"cn sw "A" and sn prnot (disabled eq "true")userName eq "john" or email co "@example.com"Operators
Section titled “Operators”| Operator | Description |
|---|---|
eq | Equals |
ne | Not equals |
co | Contains |
sw | Starts with |
ew | Ends with |
pr | Present (attribute exists) |
gt | Greater than |
ge | Greater or equal |
lt | Less than |
le | Less or equal |
Logical operators
Section titled “Logical operators”userName eq "john" and active eq trueuserName eq "john" or userName eq "jane"not (disabled eq "true")Grouping
Section titled “Grouping”Use parentheses to group conditions:
userName sw "a" and (role eq "admin" or role eq "operator")Compatibility with FleX
Section titled “Compatibility with FleX”SCIM operators are valid FleX syntax. FleX adds additional aliases:
| SCIM | FleX Alternatives |
|---|---|
eq | =, equals, is |
ne | !=, <>, is not |
co | %=, contains |
sw | ^=, starts with |
ew | $=, ends with |
pr | ?, exists, present |
gt | >, greater than, after |
ge | >=, at least, since |
lt | <, less than, before |
le | <=, at most, until |
and | implicit (whitespace), &, && |
or | ,, |, || |
not (...) | !(...), != value |
Standard LDAP filter syntax (RFC 4515) for compatibility with existing LDAP infrastructure.
Quick start
Section titled “Quick start”(cn=john)(cn=john*)(&(objectClass=user)(cn=john*))(|(cn=john)(cn=jane))(!(disabled=true))Operators
Section titled “Operators”| Pattern | Description |
|---|---|
(attr=value) | Equality |
(attr=*) | Presence (attribute exists) |
(attr=prefix*) | Starts with |
(attr=*suffix) | Ends with |
(attr=*substring*) | Contains |
(attr~=value) | Approximate match |
(attr>=value) | Greater or equal |
(attr<=value) | Less or equal |
Composite filters
Section titled “Composite filters”// AND - all must match(&(objectClass=user)(status=active)(department=Engineering))
// OR - any must match(|(cn=john)(cn=jane)(cn=bob))
// NOT - negate(!(disabled=true))
// Nested(&(objectClass=user)(|(role=admin)(role=operator)))Extensible match
Section titled “Extensible match”DN-component matching:
(member:dn:=cn=John,ou=users,dc=example,dc=com)(ou:dn:=Engineering)Migration to FleX
Section titled “Migration to FleX”| LDAP | FleX |
|---|---|
(cn=John) | cn = John |
(&(a=1)(b=2)) | a=1 b=2 |
(|(a=1)(b=2)) | a=1 or b=2 |
(!(a=1)) | a != 1 or !(a=1) |
(cn=*) | cn exists or cn? |
(cn=John*) | cn ^= John or cn starts with John |
(cn=*John) | cn $= John or cn ends with John |
(cn=*John*) | cn %= John or cn contains John |
Related
Section titled “Related”- Monitoring — Using filters in monitoring rules
- Configuration — HOCON config file reference
- Observability — Filtering telemetry data