List all users that have a certain relation with a particular object
This section will illustrate how to perform a list users request. The List Users call allows you to retrieve a list of users that have a specific relationship with a given object. This can be used in scenarios such as retrieving users who have access to a resource or managing members in a group.
Consider the following model which includes a user that can have a reader relationship with a document:Assume that you want to list all users of type user that have a reader relationship with document:planning:
Before calling the List Users API, you will need to configure the API client.
Node.js
Go
.NET
Python
Java
CLI
curl
const { CredentialsMethod, OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // https://api.us1.fga.dev, or your store's eu1/au1 region storeId: process.env.FGA_STORE_ID, authorizationModelId: process.env.FGA_MODEL_ID, credentials: { method: CredentialsMethod.ClientCredentials, config: { apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER, // auth.fga.dev apiAudience: process.env.FGA_API_AUDIENCE, // URL for your store's region clientId: process.env.FGA_CLIENT_ID, clientSecret: process.env.FGA_CLIENT_SECRET, }, },});
package mainimport ( "os" . "github.com/openfga/go-sdk/client" "github.com/openfga/go-sdk/credentials")// Configure FGA_API_URL and FGA_API_AUDIENCE for your store's us1/eu1/au1 region.// Set FGA_STORE_ID, FGA_MODEL_ID, FGA_API_TOKEN_ISSUER, FGA_CLIENT_ID, and FGA_CLIENT_SECRET.func main() { fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv("FGA_API_URL"), StoreId: os.Getenv("FGA_STORE_ID"), AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), Credentials: &credentials.Credentials{ Method: credentials.CredentialsMethodClientCredentials, Config: &credentials.Config{ ClientCredentialsApiTokenIssuer: os.Getenv("FGA_API_TOKEN_ISSUER"), ClientCredentialsApiAudience: os.Getenv("FGA_API_AUDIENCE"), ClientCredentialsClientId: os.Getenv("FGA_CLIENT_ID"), ClientCredentialsClientSecret: os.Getenv("FGA_CLIENT_SECRET"), }, }, }) if err != nil { panic(err) } _ = fgaClient // Use the client for the next request.}
using System.Collections.Generic;using OpenFga.Sdk.Client;using OpenFga.Sdk.Client.Model;using OpenFga.Sdk.Configuration;using OpenFga.Sdk.Model;using Environment = System.Environment;// FGA_API_URL and FGA_API_AUDIENCE must match the store's us1/eu1/au1 region.var fgaClient = new OpenFgaClient(new ClientConfiguration() { ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), Credentials = new Credentials() { Method = CredentialsMethod.ClientCredentials, Config = new CredentialsConfig() { ApiTokenIssuer = Environment.GetEnvironmentVariable("FGA_API_TOKEN_ISSUER"), ApiAudience = Environment.GetEnvironmentVariable("FGA_API_AUDIENCE"), ClientId = Environment.GetEnvironmentVariable("FGA_CLIENT_ID"), ClientSecret = Environment.GetEnvironmentVariable("FGA_CLIENT_SECRET"), } }});
import osfrom openfga_sdk.client import OpenFgaClient, ClientConfigurationfrom openfga_sdk.client.models import ClientTuplefrom openfga_sdk.models import RelationshipCondition, FgaObject, UserTypeFilterfrom openfga_sdk.client.models.list_users_request import ClientListUsersRequestfrom openfga_sdk.credentials import Credentials, CredentialConfiguration# FGA_API_URL and FGA_API_AUDIENCE must match the store's us1/eu1/au1 region.credentials = Credentials( method='client_credentials', configuration=CredentialConfiguration( api_issuer=os.environ.get('FGA_API_TOKEN_ISSUER'), api_audience=os.environ.get('FGA_API_AUDIENCE'), client_id=os.environ.get('FGA_CLIENT_ID'), client_secret=os.environ.get('FGA_CLIENT_SECRET'), ),)configuration = ClientConfiguration( api_url=os.environ.get('FGA_API_URL'), store_id=os.environ.get('FGA_STORE_ID'), authorization_model_id=os.environ.get('FGA_MODEL_ID'), credentials=credentials,)# Use: async with OpenFgaClient(configuration) as fga_client: ...
import dev.openfga.sdk.api.client.OpenFgaClient;import dev.openfga.sdk.api.configuration.ClientConfiguration;import dev.openfga.sdk.api.configuration.ClientCredentials;import dev.openfga.sdk.api.configuration.Credentials;import dev.openfga.sdk.api.configuration.ClientCheckOptions;import dev.openfga.sdk.api.configuration.ClientBatchCheckOptions;import dev.openfga.sdk.api.configuration.ClientWriteOptions;import dev.openfga.sdk.api.configuration.ClientListObjectsOptions;import dev.openfga.sdk.api.configuration.ClientListUsersOptions;import dev.openfga.sdk.api.client.model.*;import dev.openfga.sdk.api.model.*;import java.util.List;import java.util.Map;// FGA_API_URL and FGA_API_AUDIENCE must match the store's us1/eu1/au1 region.public class SdkSetupExample { public static void main(String[] args) throws Exception { var config = new ClientConfiguration() .apiUrl(System.getenv("FGA_API_URL")) .storeId(System.getenv("FGA_STORE_ID")) .authorizationModelId(System.getenv("FGA_MODEL_ID")) .credentials(new Credentials(new ClientCredentials() .apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER")) .apiAudience(System.getenv("FGA_API_AUDIENCE")) .clientId(System.getenv("FGA_CLIENT_ID")) .clientSecret(System.getenv("FGA_CLIENT_SECRET")))); var fgaClient = new OpenFgaClient(config); }}
# Auth0 FGA managed API: choose your store's region (us1, eu1, or au1).export FGA_API_URL=https://api.us1.fga.devexport FGA_API_AUDIENCE=https://api.us1.fga.dev/export FGA_API_TOKEN_ISSUER=auth.fga.devexport FGA_STORE_ID=YOUR_STORE_IDexport FGA_MODEL_ID=YOUR_MODEL_IDexport FGA_CLIENT_ID=YOUR_CLIENT_IDexport FGA_CLIENT_SECRET=YOUR_CLIENT_SECRET# Obtain these values from https://dashboard.fga.dev/ and keep credentials private.
# Requires jq to safely encode credentials as JSON.curl -sS -X POST 'https://auth.fga.dev/oauth/token' \ -H 'content-type: application/json' \ --data "$(jq -n \ --arg client_id "$FGA_CLIENT_ID" \ --arg client_secret "$FGA_CLIENT_SECRET" \ --arg audience "$FGA_API_AUDIENCE" \ '{client_id: $client_id, client_secret: $client_secret, audience: $audience, grant_type: "client_credentials"}')"# Use the access_token in the response as FGA_BEARER_TOKEN for direct API calls.
To return all users of type user that have have the reader relationship with document:planning:The result user:anne and user:beth are the user objects that have the reader relationship with document:planning.
WarningThe 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.
In the above example, only specific subjects of the user type were returned. However, groups of users, known as usersets, 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.Below is an example where usersets can be returned:With the tuples:
user
relation
object
group:engineering#member
viewer
document:1
group:product#member
viewer
document:1
user:will
member
group:engineering
Then calling the List Users API for document:1 with relation viewer of type group#member will yield the below response. Note that the user:will is not returned, despite being a member of group:engineering#member because the user_filters does not target the user type.
The List Users API supports tuples expressing public access via the wildcard syntax (e.g. user:*). Wildcard tuples that satisfy the query criteria will be returned with the wildcard root object property that will specify the type. A typed-bound public access result indicates that the object has a public relation but it doesn’t necessarily indicate that all users of that type have that relation, it is possible that exclusions via the but not syntax exists. The API will not expand wildcard results further to any ID’d user object. Further, specific users that have been granted access will be returned in addition to any public access for that user’s type.
A List Users response with a type-bound public access result (e.g. user:*) doesn’t necessarily indicate that all users of that type have access, it is possible that exclusions exist. It is recommended to perform a Check on specific users to ensure they have access to the target object.