- Stored attributes: Attributes persisted in OpenFGA as part of your relationship data
- Request-time attributes: Dynamic attributes sent with each authorization check request
Stored Attribute Data
When attributes are relatively static and can be stored alongside your relationship data, you can model them directly in OpenFGA. This approach works well for attributes like “email verified”, “SSO enabled”, or “account tier”. Consider a scenario where you want to allow users to perform an action only if their organization has SSO enabled. Below are three patterns for modeling this requirement.Modeling Attributes as Relations
Using user:* as a Boolean Flag
The simplest approach for boolean attributes is using the Public Access pattern. By assigning user:* to a relation, you effectively create a boolean flag that applies to all users.
When to use this approach:
- You need a simple true/false flag
- The attribute applies uniformly to all users in a context
- You want minimal tuple overhead
Using Self-Relations
An alternative approach is to use a self-referential relation, where an object points to itself to indicate an attribute is set. This pattern makes the relationship semantics more explicit. When to use this approach:- You want clearer semantics about what the attribute represents
- The attribute is a property of the object itself rather than a universal grant
- You prefer explicit object references over wildcards
Storing Attributes in Conditional Tuple Context
For attributes that require typed values beyond simple booleans, you can store the attribute value directly in the condition context of a relationship tuple. This approach combines the relationship with its associated attribute data. When to use this approach:- You need typed attribute values (strings, numbers, etc.)
- The attribute is tightly coupled to a specific relationship
- You want to avoid additional tuples for attribute storage
Request-Time Attribute Data
Some attributes cannot be stored because they are dynamic and change with each request. Common examples include the current time, client IP address, or the user’s current session context. For these scenarios, you provide the attribute values at request time. For time-based, IP-based conditions and more, see the Conditions documentation for detailed examples.Multi-Organization Session Context
A common use case is when users can authenticate to multiple organizations but should only access resources belonging to their currently active organization. When accessing content, you need to verify the content belongs to the organization the user is currently logged into. You can achieve this with either contextual tuples or conditional relationship tuples.Using Contextual Tuples
With this approach, you add a relation (e.g.,user_in_context) that is not stored but sent as a contextual tuple with each request. This contextual tuple represents the user’s current session context.
When to use this approach:
- Session context is determined entirely at request time
- You want to keep stored tuples simple and context-free
- The context applies across multiple relation checks
Using Conditional Relationship Tuples
Instead of adding contextual tuples, you can attach conditions to your stored relationship tuples and provide the context values at request time. The condition compares stored values against request-time values. When to use this approach:- You want to avoid sending contextual tuples with every request
- The condition logic involves comparing stored and request-time values
- You prefer conditions over additional relations in your model
Choosing the Right Approach
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
Related Sections
Check out these related resources for more information about ABAC patterns in OpenFGAConditions
Learn how to use conditions for time-based, IP-based, and other dynamic checks.
Contextual Tuples
Understand how to send dynamic relationship data with each request.
Public Access
Learn about the user:* pattern for granting access to everyone.
Modular Authorization Models
Learn how to break down your authorization model into modules.