Skip to main content

Relationship Queries: Check, Read, Expand, ListObjects and ListUsers

In this guide you will learn the uses of and limitations for the Check, Read, Expand, ListObjects and ListUsers API endpoints.

Before you start

In order to understand this guide correctly you must be familiar with some Auth0 FGA Concepts and know how to develop the things that we will list below.

Assume that you have the following authorization model.
You have a type called document that can have a reader and writer. All writers are readers. bob has a writer relationship with document:planning.

model
schema 1.1

type user

type document
relations
define writer: [user]
define reader: [user] or writer
[// Bob has writer relationship with planning document
{
"_description": "Bob has writer relationship with planning document",
"user": "user:bob",
"relation": "writer",
"object": "document:planning"
}]

In addition, you will need to know the following:

Direct access

You need to know how to create an authorization model and create a relationship tuple to grant a user access to an object. Learn more →

Auth0 FGA concepts

  • A Type: a class of objects that have similar characteristics
  • A User: an entity in the system that can be related to an object
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in Auth0 FGA

Check

What is it for?

The Check API is an API endpoint that returns whether the user has a certain relationship with an object. Auth0 FGA will resolve all prerequisite relationships to establish whether a relationship exists.

When to use?

Check can be called if you need to establish whether a particular user has a specific relationship with a particular object.

For example, you can call check to determine whether bob has a reader relationship with document:planning.

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'reader',
object: 'document:planning',
}, {
authorizationModelId: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true

The Auth0 FGA API will return true because there is an implied relationship as

  • every writer is also a reader
  • bob is a writer for document:planning

Limits

Check out the request rate limits for your plan.

Caveats and when not to use it

Check is designed to answer the question "Does user:X have relationship Y with object:Z?". It is not designed to answer the following questions:

  • "Who has relationship Y with object:Z?"
  • "What are the objects that userX has relationship Y with?"
  • "Why does user:X have relationship Y with object:Z?"

Batch Check

What is it for?

The Batch Check API is an API endpoint that allows you to check multiple user-object-relationship combinations in a single request.

When to use?

Batching authorization checks together in a single request significantly reduces overall network latency.

Two scenarios are common to use Batch Check:

  1. When determining if the user has access to a list of objects (such as Option 1 in Search with Permissions), filter and sort on your database, then call /batch-check. Repeat to perform pagination.
  2. When determining fields on a web page the user has access to, call /batch-check for every relation necessary to show/hide each field.

For example, you can call Batch Check to determine whether bob has can_view_name, can_view_dob, and can_view_ssn relationships with patient_record:1.

const body = {
checks: [
{
user: 'user:bob',
relation: 'can_view_name',
object: 'patient_record:1',
correlationId: '1'
},{
user: 'user:bob',
relation: 'can_view_dob',
object: 'patient_record:1',
correlationId: '2'
},{
user: 'user:bob',
relation: 'can_view_ssn',
object: 'patient_record:1',
correlationId: '3'
}
],
}

const options = {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
maxBatchSize: 50, // optional, default is 50, can be used to limit the number of checks in a single server request
maxParallelRequests: 10, // optional, default is 10, can be used to limit the parallelization of the BatchCheck chunks
};
const { result } = await fgaClient.batchCheck(body, options);

/*
{
"results": [
{
"correlationId": '1',
"allowed": true,
"request": {
"user": 'user:bob',
"relation": 'can_view_name',
"object": 'patient_record:1'}
}, {
"correlationId": '2',
"allowed": true,
"request": {
"user": 'user:bob',
"relation": 'can_view_dob',
"object": 'patient_record:1'}
}, {
"correlationId": '3',
"allowed": false,
"request": {
"user": 'user:bob',
"relation": 'can_view_ssn',
"object": 'patient_record:1'}
}
],
}
*/

The Auth0 FGA API will return true depending on the level of access assigned to that user and the implied relationships inherited in the authorization model.

Caveats and when not to use it

If you are making less than 10 checks, it may be faster to call the Check API in parallel instead of Batch Check.

Read

What Is It For?

The Read API is an API endpoint that returns the relationship tuples that are stored in the system that satisfy a query.

When to use?

Read can be called if you need to get all the stored relationship tuples that relate:

  1. user + relation + object
  2. user + relation + object type
  3. user + object with any relation
  4. user + object type with any relation
  5. relation + object for any user
  6. object with any user and relation
  7. all with any user, relation, or object

For example, to query if bob has a writer relationship on document:planning (essentially finding out if a tuple exists), one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
user:'user:bob',
relation:'writer',
object:'document:planning',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

For example, to query all the stored relationship tuples bob has a writer relationship with on type document:, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
user:'user:bob',
relation:'writer',
object:'document:',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

For example, to query all the stored relationship tuples bob has on type document:planning, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
user:'user:bob',
object:'document:planning',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

For example, to query all the stored relationship tuples bob has on object type document:, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
user:'user:bob',
object:'document:',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

For example, to query all the stored relationship tuples which have the writer relation on object document:planning, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
relation:'writer',
object:'document:planning',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

For example, to query all the stored relationship tuples for object document:planning, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
object:'document:planning',
});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

7. Read all tuples for any user, relation, or object

For example, to query all stored relationship tuples, one can ask

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({

});

// tuples = [{"key": {"user":"user:bob","relation":"writer","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]

Limits

Check out the request rate limits for your plan.

Caveats and when not to use it

The Read API will only return all the stored relationships that match the query specification. It does not expand or traverse the graph by taking the authorization model into account.

For example, if you specify that writers are viewers in the authorization model, the Read API will ignore that and it will return tuples where a user is a viewer if and only if the (user_id, "viewer", object_type:object_id) relationship tuple exists in the system.

In the following case, although all writers have reader relationships for document objects and bob is a writer for document:planning, if you query for all objects that bob has reader relationships, it will not return document:planning.

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

// Execute a read
const { tuples } = await fgaClient.read({
user:'user:bob',
relation:'reader',
object:'document:',
});

// tuples = []
info

Although bob is a writer to document:planning and every writer is also a reader, the Read API will return an empty list because there are no stored relationship tuples that relate bob to document:planning as reader.

Expand

What is it for?

The Expand API returns all users (including users and usersets) that have a specific relationship with an object. The response is represented as a tree of users or usersets. To build the full graph of access, you would need to recursively call expand on the leaves returned from the previous expand call.

When to use?

Expand is used for debugging and to understand why a user has a particular relationship with a specific object.

For example, to understand why bob can have a reader relationship with document:planning, one could first call

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

const { tree } = await fgaClient.expand({
relation: 'reader', // expand all who has 'reader' relation
object: 'document:planning', // with the object 'document:planning'
}, {
authorizationModelId: '01HVMMBCMGZNT3SED4Z17ECXCA'
});

// tree = ...

The result of this call will be like

{
"tree":{
"root":{
"type":"document:planning#reader",
"leaf":{
"computed":{
"userset":"document:planning#writer"
}
}
}
}
}
}

The returned tree will contain writer, for which we will call

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});

const { tree } = await fgaClient.expand({
relation: 'writer', // expand all who has 'writer' relation
object: 'document:planning', // with the object 'document:planning'
}, {
authorizationModelId: '01HVMMBCMGZNT3SED4Z17ECXCA'
});

// tree = ...

The result of this call will be like

{
"tree":{
"root":{
"type":"document:planning#writer",
"leaf":{
"users":{
"users":[
"user:bob"
]
}
}
}
}
}
}

From there, we will learn that

  • those related to document:planning as reader are all those who are related to that document as writer
  • bob is related to document:planning as writer

Limits

Check out the request rate limits for your plan.

ListObjects

What is it for?

The ListObjects API is an API endpoint that returns the list of all the objects of a particular type that a specific user has a specific relationship with.

It provides a solution to the Search with Permissions (Option 3) use case for access-aware filtering on small object collections.

When to use?

Use the ListObjects API to get what objects a user can see based on the relationships they have. See Search with Permissions for more guidance.

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});
const response = await fgaClient.listObjects({
user: "user:bob",
relation: "reader",
type: "document",
contextualTuples: {
tuple_keys: [{
user: "user:bob",
relation: "reader",
object: "document:otherdoc"
}]
},
}, {
authorizationModelId: "01HVMMBCMGZNT3SED4Z17ECXCA",
});
// response.objects = ["document:otherdoc", "document:planning"]

There's two variations of the List Objects API.

  • The standard version, which waits until all results are ready and sends them in one response.
  • The streaming version, which should be used if you want the individual results as soon as they become available.

Limits

Check out the request rate limits for your plan.

Caveats

ListObjects will return the results found within the time allotted (3s).

ListUsers

What is it for?

The ListUsers API is an API endpoint that that returns all users of a given type that have a specified relationship with an object.

When to use?

Use the ListUsers API to get which users have a relation to a specific object.

Initialize the SDK
// Checkout the "How to Setup the SDK Client" page for more details.
const { CredentialsMethod, OpenFgaClient } = require('@openfga/sdk'); // OR import { CredentialsMethod, OpenFgaClient } from '@openfga/sdk';

// Ensure the environment variables are set
// FGA_API_URL = 'https://api.us1.fga.dev' // 'https://api.eu1.fga.dev' for EU and 'https://api.au1.fga.dev' for AU
// FGA_STORE_ID = 'YOUR_STORE_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_MODEL_ID = 'YOUR_MODEL_ID' - optional, can be overridden per request, helps reduce latency
// FGA_API_TOKEN_ISSUER = 'auth.fga.dev'
// FGA_API_AUDIENCE = 'https://api.us1.fga.dev/' // 'https://api.eu1.fga.dev/' for EU and 'https://api.au1.fga.dev/' for AU
// FGA_CLIENT_ID = 'YOUR_CLIENT_ID' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page
// FGA_CLIENT_SECRET = 'YOUR_CLIENT_SECRET' - Get this from your store settings in the dashboard, refer to the "How to get your API Keys" page

const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID,
credentials: { // Credentials are not needed if connecting to the Playground API
method: CredentialsMethod.ClientCredentials,
config: {
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER,
apiAudience: process.env.FGA_API_AUDIENCE,
clientId: process.env.FGA_CLIENT_ID,
clientSecret: process.env.FGA_CLIENT_SECRET,
},
},
});
const response = await fgaClient.listUsers({
object: {
type: "document",
id: "planning"
},
user_filters: [{
type: "user"
}],
relation: "viewer",
}, {
authorizationModelId: "01HVMMBCMGZNT3SED4Z17ECXCA",
});
// response.users = [{"object":{"type":"user","id":"anne"}},{"object":{"type":"user","id":"beth"}}]

Caveats

ListUsers will return the results found within the time allotted (3s).

Summary

CheckReadExpandListObjectsListUsers
PurposeCheck if user has particular relationship with certain objectReturn all stored relationship tuples that match queryExpand the specific relationship on a particular objectList all objects of a particular type that a user has a specific relationship withList all users of a particular type that have a relation to a specific object
When to useValidate if user X can perform Y on object ZList stored relationships in systemUnderstand why user X can perform Y on object ZFilter the objects a user has access toList the users that have access to an object
Check API Reference

Official reference guide for the Check API

Read API Reference

Official reference guide for the Read API

Expand API Reference

Official reference guide for the Expand API

ListObjects API Reference

Official reference guide for the ListObjects API

ListUsers API Reference

Official reference guide for the ListUsers API

Have Feedback?

You can use any of our support channels for any questions or suggestions you may have.