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,
},
},
});
async function main() {
const body = {
"relation": "reader",
"object": "document:budget"
};
const response = await fgaClient.expand(body);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"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) }
body := ClientExpandRequest{
Relation: "reader",
Object: "document:budget",
}
response, err := fgaClient.Expand(context.Background()).Body(body).Execute()
if err != nil {
panic(err)
}
_ = response
}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"),
}
}
});
var body = new ClientExpandRequest {
Relation = "reader",
Object = "document:budget",
};
var response = await fgaClient.Expand(body);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientCheckRequest, ClientTuple
from openfga_sdk.models import RelationshipCondition
from 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'),
),
)
from openfga_sdk.client.models import ClientExpandRequest
async def main():
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,
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientExpandRequest(
relation="reader",
object="document:budget",
)
response = await fga_client.expand(body=body)
asyncio.run(main())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 Example {
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);
var body = new ClientExpandRequest()
.relation("reader")
._object("document:budget");
var response = fgaClient.expand(body).get();
}
}# Set FGA_API_URL to your store region (https://api.us1.fga.dev, or eu1/au1).
# Set FGA_STORE_ID and obtain FGA_BEARER_TOKEN with the client credentials grant.
# See /integration/getting-your-api-keys; never put client secrets in source code.
curl -X POST "$FGA_API_URL/stores/$FGA_STORE_ID/expand" \
-H "authorization: Bearer $FGA_BEARER_TOKEN" \
-H "content-type: application/json" \
-d '{
"tuple_key": {
"relation": "reader",
"object": "document:budget"
}
}'{
"tree": {
"root": {
"name": "<string>",
"difference": {
"base": "<unknown>",
"subtract": "<unknown>"
},
"intersection": {
"nodes": "<array>"
},
"leaf": {
"computed": {
"userset": "<string>"
},
"tupleToUserset": {
"computed": [
{
"userset": "<string>"
}
],
"tupleset": "<string>"
},
"users": {
"users": [
"<string>"
]
}
},
"union": {
"nodes": "<array>"
}
}
}
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthorized_principal",
"message": "Missing permissions to perform operation"
}{
"code": "unauthorized_principal",
"message": "Missing permissions to perform operation"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "rate_limit_exceeded",
"message": "Rate Limit exceeded"
}{
"code": "internal_error",
"message": "Internal Server Error"
}Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason about and debug a certain relationship
The Expand API will return all users and usersets that have certain relationship with an object in a certain store.
This is different from the /stores/{store_id}/read API in that both users and computed usersets are returned.
Body parameters tuple_key.object and tuple_key.relation are all required.
The response will return a tree whose leaves are the specific users and usersets. Union, intersection and difference operator are located in the intermediate nodes.
Example
To expand all users that have the reader relationship with object document:2021-budget, use the Expand API with the following request body
{
"tuple_key": {
"object": "document:2021-budget",
"relation": "reader"
},
"authorization_model_id": "01G50QVV17PECNVAHX1GG4Y5NC"
}
Auth0 FGA’s response will be a userset tree of the users and usersets that have read access to the document.
{
"tree":{
"root":{
"type":"document:2021-budget#reader",
"union":{
"nodes":[
{
"type":"document:2021-budget#reader",
"leaf":{
"users":{
"users":[
"user:bob"
]
}
}
},
{
"type":"document:2021-budget#reader",
"leaf":{
"computed":{
"userset":"document:2021-budget#writer"
}
}
}
]
}
}
}
}
The caller can then call Expand API for the writer relationship for the document:2021-budget.
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,
},
},
});
async function main() {
const body = {
"relation": "reader",
"object": "document:budget"
};
const response = await fgaClient.expand(body);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"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) }
body := ClientExpandRequest{
Relation: "reader",
Object: "document:budget",
}
response, err := fgaClient.Expand(context.Background()).Body(body).Execute()
if err != nil {
panic(err)
}
_ = response
}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"),
}
}
});
var body = new ClientExpandRequest {
Relation = "reader",
Object = "document:budget",
};
var response = await fgaClient.Expand(body);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientCheckRequest, ClientTuple
from openfga_sdk.models import RelationshipCondition
from 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'),
),
)
from openfga_sdk.client.models import ClientExpandRequest
async def main():
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,
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientExpandRequest(
relation="reader",
object="document:budget",
)
response = await fga_client.expand(body=body)
asyncio.run(main())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 Example {
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);
var body = new ClientExpandRequest()
.relation("reader")
._object("document:budget");
var response = fgaClient.expand(body).get();
}
}# Set FGA_API_URL to your store region (https://api.us1.fga.dev, or eu1/au1).
# Set FGA_STORE_ID and obtain FGA_BEARER_TOKEN with the client credentials grant.
# See /integration/getting-your-api-keys; never put client secrets in source code.
curl -X POST "$FGA_API_URL/stores/$FGA_STORE_ID/expand" \
-H "authorization: Bearer $FGA_BEARER_TOKEN" \
-H "content-type: application/json" \
-d '{
"tuple_key": {
"relation": "reader",
"object": "document:budget"
}
}'{
"tree": {
"root": {
"name": "<string>",
"difference": {
"base": "<unknown>",
"subtract": "<unknown>"
},
"intersection": {
"nodes": "<array>"
},
"leaf": {
"computed": {
"userset": "<string>"
},
"tupleToUserset": {
"computed": [
{
"userset": "<string>"
}
],
"tupleset": "<string>"
},
"users": {
"users": [
"<string>"
]
}
},
"union": {
"nodes": "<array>"
}
}
}
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthorized_principal",
"message": "Missing permissions to perform operation"
}{
"code": "unauthorized_principal",
"message": "Missing permissions to perform operation"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "rate_limit_exceeded",
"message": "Rate Limit exceeded"
}{
"code": "internal_error",
"message": "Internal Server Error"
}Authorizations
The access token received from the authorization server in the OAuth 2.0 flow.
Path Parameters
Body
Show child attributes
Show child attributes
"01G5JAVJ41T49E9TT3SKVS7X1J"
Controls the consistency preference for this request. Default value is UNSPECIFIED, which will have the same behavior as MINIMIZE_LATENCY.
UNSPECIFIED, MINIMIZE_LATENCY, HIGHER_CONSISTENCY "MINIMIZE_LATENCY"
Show child attributes
Show child attributes
Response
A successful response.
A UsersetTree contains the result of an Expansion.
Show child attributes
Show child attributes