“Given a particular search filter and a sort order, what objects can the user access”?The Auth0 FGA service does not store object metadata (names of files, creation dates, time of last update, etc), adding filtering and sorting on top of any search query will require data from your database. The services responsible for performing these actions are:
- Access: Auth0 FGA
- Filter: Your database
- Sort: Your database
Possible options
There are four possible ways to do this:Option 1: Search, then check
Pre-filter, then call the Batch Check API.- Filter and sort on your database.
- Call
/batch-checkto check access for multiple objects in a single request. - Filter out objects the user does not have access to.
- Return the filtered result to the user.
Option 2: Fetch a list of authorized IDs, then search
Call the List Objects API to get a list of object IDs the user has access to, then run the filter restricting by the object IDs returned.- Call
/list-objectsto get the list of all resources a user can access. - Pass in the set of object IDs to the database query to limit the search.
- Return the filtered result to the user.
and or but not are more expensive to evaluate than relations with or.
Option 3: Use FGA Permissions Index
Auth0 FGA offers a Permissions Index to continually maintain a fully “flattened” set of permissions. The Permissions index pre-calculates all permission combinations at write time and stores them as direct user-to-object relationships for constant lookup at query time.- Create a Permissions Index in Auth0 FGA.
- Stream expansion changes into your local database, such as PostgreSQL, Snowflake, or ElasticSearch.
- Join or filter between your business data and the colocated permissions index.
Option 4: Build a local index from changes endpoint, then search
Consume the Changes API to create a local index you can use to do an intersection on the two sets of results.- Call the
/changesendpoint to get every tuple write or delete event. - For the particular authorization model version(s) you are using in production, flatten/expand the changes
- (e.g.
user:anne, writer, doc:planningbecomes two tuples:user:anne, writer, doc:planninganduser:anne, reader, doc:planning).
- (e.g.
- Build the intersection query between the objects in your database and the flattened/expanded index you created.
Choosing the best option
Which option to choose among the four listed above depends on the following criteria:- Number of objects that your database can return from a search query
- Number of objects of a certain type the user could have access to
- Percentage of objects in a type the user could have access to
GET /list-objects would make sense. You can query this API to get a list of object IDs and then pass these IDs to your filter function to limit the search to them.
As this number increases, this solution becomes impractical, because you would need to paginate over multiple pages to get the entire list before being able to search and sort. A partial list from the API is not enough, because you won’t be able to sort using it.
So while List of IDs then Search would be useful for this in some situations, we would recommend Use the Permissions Index or Local Index from Changes Endpoint, Search then Check for the cases when the number of objects is high enough.
D. The number of objects of a certain type the user could have access to is high, and the percentage of the total objects that the user can have access to is low.
The recommended option for this case is to use Use the Permissions Index or Local Index from Changes Endpoint, Search then Check.
- List of IDs then Search would not work because you would have to get and paginate across thousands or tens of thousands (or in some cases more) of results from Auth0 FGA, only after you have retrieved the entire set can you start searching within your database for matching results. This would mean that your user could be waiting for a long time before they can start seeing results.
- Search then Check would also not be ideal, as you will be retrieving and checking against a lot of items and discarding most of them.
- Duplicate logic from the authorization model when querying your database. For example, in a multi-tenant scenario, you can filter all resources based on the tenant the user is logged-in to. Duplicating logic from the authorization model is not ideal, but it can be a reasonable trade-off.
- Retrieve a higher-level resource ID list with lower cardinality for efficient filtering. For example, in a document management application, first obtain the list of accessible folders for the user. You can then filter documents by these folders in your database query. This approach increases the likelihood that the user can access the documents in those folders, optimizing the query’s effectiveness.