Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/content/best-practices/modeling-abac.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ When deciding between these approaches, consider:
- **Data volatility**: Use stored attributes for stable data, request-time attributes for dynamic data
- **Model complexity**: Start with simpler patterns (like `user:*`) and evolve to more complex ones as needed
- **Attribute types**: Use conditions when you need typed values beyond booleans
- **Enumeration queries**: Stored-attribute patterns (relationship tuples) work fully with [ListObjects](../getting-started/perform-list-objects.mdx) and [ListUsers](../getting-started/perform-list-users.mdx) without requiring context. Conditional relationship tuples have limitations with these queries — if a condition parameter varies per user, ListUsers cannot supply the correct value for each candidate, and similarly for ListObjects with per-object attributes not stored in the tuple context. See [Conditions: Limitations](../modeling/conditions.mdx#conditions-and-enumeration-queries-listobjects--listusers) for details
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add missing period at end of sentence.

The line ends with "for details" but is missing a period.

Punctuation fix
-- **Enumeration queries**: Stored-attribute patterns (relationship tuples) work fully with [ListObjects](../getting-started/perform-list-objects.mdx) and [ListUsers](../getting-started/perform-list-users.mdx) without requiring context. Conditional relationship tuples have limitations with these queries — if a condition parameter varies per user, ListUsers cannot supply the correct value for each candidate, and similarly for ListObjects with per-object attributes not stored in the tuple context. See [Conditions: Limitations](../modeling/conditions.mdx#conditions-and-enumeration-queries-listobjects--listusers) for details
+- **Enumeration queries**: Stored-attribute patterns (relationship tuples) work fully with [ListObjects](../getting-started/perform-list-objects.mdx) and [ListUsers](../getting-started/perform-list-users.mdx) without requiring context. Conditional relationship tuples have limitations with these queries — if a condition parameter varies per user, ListUsers cannot supply the correct value for each candidate, and similarly for ListObjects with per-object attributes not stored in the tuple context. See [Conditions: Limitations](../modeling/conditions.mdx#conditions-and-enumeration-queries-listobjects--listusers) for details.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/best-practices/modeling-abac.mdx` at line 347, Add a period at
the end of the sentence in the "Enumeration queries" paragraph so the final
clause reads "...See Conditions: Limitations for details." Locate the paragraph
that begins with the bold heading "Enumeration queries" and references
ListObjects and ListUsers and append a trailing period after "for details".


## Related Sections

Expand Down
4 changes: 4 additions & 0 deletions docs/content/getting-started/perform-list-objects.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ The result `document:otherdoc` and `document:planning` are the document objects
The performance characteristics of the ListObjects endpoint vary drastically depending on the model complexity, number of tuples, and the relations it needs to evaluate. Relations with 'and' or 'but not' are more expensive to evaluate than relations with 'or'.
:::

:::info Conditions and List Objects
When a relation uses a [condition](../modeling/conditions.mdx) with a per-object attribute that is NOT stored in the tuple context, the List Objects API may not return correct results. The API accepts a single `context` per call, but each candidate object may have a different value for that attribute. If the per-object attribute is stored in the tuple context (written alongside the relationship tuple), ListObjects works correctly because the value is resolved per tuple. See [Conditions: Limitations](../modeling/conditions.mdx#conditions-and-enumeration-queries-listobjects--listusers) for details.
:::

## Streamed List Objects

The Streamed ListObjects API is similar to the ListObjects API, with two key differences:
Expand Down
4 changes: 4 additions & 0 deletions docs/content/getting-started/perform-list-users.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ The result `user:anne` and `user:beth` are the `user` objects that have the `rea
The performance characteristics of the List Users endpoint vary drastically depending on the model complexity, number of tuples, and the relations it needs to evaluate. Relations with 'and' or 'but not' are particularly expensive to evaluate.
:::

:::info Conditions and List Users
When a relation uses a [condition](../modeling/conditions.mdx) with a per-user attribute (e.g., `user_clearance`), the List Users API may not return correct results. The API accepts a single `context` per call, but each candidate user may have a different value for that attribute. If you need to enumerate users based on a per-user attribute comparison, consider modeling the attribute as a [type hierarchy using relationship tuples](../best-practices/modeling-abac.mdx) instead of a condition. See [Conditions: Limitations](../modeling/conditions.mdx#conditions-and-enumeration-queries-listobjects--listusers) for details.
:::

## Usersets

In the above example, only specific subjects of the `user` type were returned. However, groups of users, known as [usersets](../modeling/building-blocks/usersets.mdx), can also be returned from the List Users API. This is done by specifying a `relation` field in the `user_filters` request object. Usersets will only expand to the underlying subjects if that `type` is specified as the user filter object.
Expand Down
22 changes: 22 additions & 0 deletions docs/content/modeling/conditions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,28 @@ Note that some of the types support generics, these types are indicated with `<T


## Limitations

### Conditions and enumeration queries (ListObjects / ListUsers)

The Check, ListObjects, and ListUsers APIs all accept a single `context` per call. This means every condition parameter must have one value for the entire query. When a condition compares a per-user attribute against a per-object attribute, one side varies across the enumeration set and cannot be supplied as a single value:

- **ListObjects** iterates over objects. If a condition parameter is a per-object attribute that is NOT stored in the tuple context, it varies across the enumeration set and there is no single value to pass.
- **ListUsers** iterates over users. If a condition parameter is a per-user attribute, it varies across the enumeration set and there is no single value to pass.
- **Check** evaluates a single (user, object) pair. Both sides are fixed, so conditions always work.
Comment on lines +264 to +268

For example, consider a condition `clearance_sufficient(user_clearance: int, resource_sensitivity: int)` where `resource_sensitivity` is stored in the tuple context and `user_clearance` is passed at request time:

- **ListObjects** works: the user is fixed (one `user_clearance` value to pass), and `resource_sensitivity` is resolved per tuple from the stored context.
- **ListUsers** does not work as expected: each candidate user has a different `user_clearance`, but only one value can be passed per call.

If you need both ListObjects and ListUsers to work for a level-based comparison, consider modeling the levels as a [type hierarchy using relationship tuples](../best-practices/modeling-abac.mdx) instead of conditions.

### Tuple uniqueness

A conditional tuple shares the same uniqueness constraint as any other tuple: the triple `(user, relation, object)` must be unique. You cannot write two tuples with the same user, relation, and object but different condition names or different condition context values. If you need multiple conditional relationships for the same subject-object pair, introduce an intermediary type so each instance gets a unique object ID.

### Size and cost limits

* The size of the condition `context` parameter that can be written alongside a relationship tuple is limited to 32KB in size.

* The size of the condition `context` parameter for query requests (e.g. Check, ListObjects, etc.) is not explicitly limited, but the OpenFGA server has an overall request size limit of 512KB at this time.
Expand Down
Loading