Object to Object Relationships
In this guide you'll learn how to model your application with objects that are not specifically tied to a user. For example, a folder
is a parent
of a document
.
This design pattern is helpful in the case where there are relationships between different objects. With OpenFGA, so long as both objects are in a type defined in the authorization model, relationship tuples can be added to indicate a relationship between them.
For example:
communities
can containchannels
channels
can containposts
channels
can containthreads
threads
can containposts
bookshelf
can havebooks
trips
can havebookings
account
can containtransactions
buildings
can havedoors
Before you start
To better follow this guide, make sure you're familiar with some OpenFGA Concepts and know how to develop the things listed below.
You will start with the authorization model below, it represents a document
type that can have users related as editor
, and folder
type that can have users related as viewer
.
document
type that can have users related as editor
, and folder
type that can have users related as viewer
.- DSL
- JSON
model
schema 1.1
type user
type document
relations
define editor: [user]
type folder
relations
define viewer: [user]
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "document",
"relations": {
"editor": {
"this": {}
}
},
"metadata": {
"relations": {
"editor": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
},
{
"type": "folder",
"relations": {
"viewer": {
"this": {}
}
},
"metadata": {
"relations": {
"viewer": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
In addition, you will need to know the following:
Modeling user groups
You need to know how to add users to groups and grant groups access to resources. Learn more →
OpenFGA 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 OpenFGA
Step by step
01. Create parent relations in document
To represent that a folder
can be a parent
of a document
, we first need to modify our document
type definition to allow a parent
relation.
- DSL
- JSON
model
schema 1.1
type user
type document
relations
define parent: [folder]
define editor: [user]
type folder
relations
define viewer: [user]
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "document",
"relations": {
"parent": {
"this": {}
},
"editor": {
"this": {}
}
},
"metadata": {
"relations": {
"parent": {
"directly_related_user_types": [
{
"type": "folder"
}
]
},
"editor": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
},
{
"type": "folder",
"relations": {
"viewer": {
"this": {}
}
},
"metadata": {
"relations": {
"viewer": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
02. Add Parent Relationship Tuples
Once the type definition is updated, we can now create the relationship between a folder
as a parent
of a document
. To do this, we will create a new relationship tuple that describes: folder:budgets is a parent
of document:may_budget.doc. In OpenFGA, users in the relationship tuples can not only be IDs, but also other objects in the form of type:object_id
.
- Node.js
- Go
- .NET
- Python
- Java
- curl
- CLI
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
await fgaClient.write({
writes: [
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
{"_description":"The user in this case is another object where the type is `folder` and the object_id is `budgets`","user":"folder:budgets","relation":"parent","object":"document:may_budget.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientWriteOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientWriteRequest{
Writes: []ClientTupleKey{
{
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
User: "folder:budgets",
Relation: "parent",
Object: "document:may_budget.doc",
},
},
}
data, err := fgaClient.Write(context.Background()).
Body(body).
Options(options).
Execute()
if err != nil {
// .. Handle error
}
_ = data // use the response
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientWriteOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientWriteRequest() {
Writes = new List<ClientTupleKey>() {
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
new() {
User = "folder:budgets",
Relation = "parent",
Object = "document:may_budget.doc"
}
},
};
var response = await fgaClient.Write(body, options);
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientWriteRequest(
writes=[
ClientTuple(
# The user in this case is another object where the type is `folder` and the object_id is `budgets`
user="folder:budgets",
relation="parent",
object="document:may_budget.doc",
),
],
)
response = await fga_client.write(body, options)
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientWriteOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientWriteRequest()
.writes(List.of(
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
new ClientTupleKey()
.user("folder:budgets")
.relation("parent")
._object("document:may_budget.doc")
));
var response = fgaClient.write(body, options).get();
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"writes": { "tuple_keys" : [{"_description":"The user in this case is another object where the type is `folder` and the object_id is `budgets`","user":"folder:budgets","relation":"parent","object":"document:may_budget.doc"}] }, "authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"}'
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga tuple write --store-id=${FGA_STORE_ID} --model-id=01HVMMBCMGZNT3SED4Z17ECXCA folder:budgets parent document:may_budget.doc
write([
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
{
"user":"folder:budgets",
"relation":"parent",
"object":"document:may_budget.doc"
}
], authorization_model_id="01HVMMBCMGZNT3SED4Z17ECXCA")
03. Check that parent folders have permissions
Once that relationship tuple is added to OpenFGA, we can check if the relationship is valid by asking the following: "is folder:budgets a parent of document:may_budget.doc?"
- Node.js
- Go
- .NET
- Python
- Java
- CLI
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
// Run a check
const { allowed } = await fgaClient.check({
user: 'folder:budgets',
relation: 'parent',
object: 'document:may_budget.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientCheckOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientCheckRequest{
User: "folder:budgets",
Relation: "parent",
Object: "document:may_budget.doc",
}
data, err := fgaClient.Check(context.Background()).
Body(body).
Options(options).
Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientCheckOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientCheckRequest {
User = "folder:budgets",
Relation = "parent",
Object = "document:may_budget.doc",
};
var response = await fgaClient.Check(body, options);
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientCheckRequest(
user="folder:budgets",
relation="parent",
object="document:may_budget.doc",
)
response = await fga_client.check(body, options)
# response.allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientCheckOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientCheckRequest()
.user("folder:budgets")
.relation("parent")
._object("document:may_budget.doc");
var response = fgaClient.check(body, options).get();
// response.getAllowed() = true
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga query check --store-id=$FGA_STORE_ID --model-id=01HVMMBCMGZNT3SED4Z17ECXCA folder:budgets parent document:may_budget.doc
# Response: {"allowed":true}
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA", "tuple_key":{"user":"folder:budgets","relation":"parent","object":"document:may_budget.doc"}}'
# Response: {"allowed":true}
check(
user = "folder:budgets", // check if the user `folder:budgets`
relation = "parent", // has an `parent` relation
object = "document:may_budget.doc", // with the object `document:may_budget.doc`
authorization_id = "01HVMMBCMGZNT3SED4Z17ECXCA"
);
Reply: true
It is important to note that the current authorization model does not imply inheritance of permissions. Even though folder:budgets is a parent
of document:may_budget.doc, it does not inherit the editor
relation from parent
to document
. Meaning editors
on folder:budgets are not editors
on document:may_budget.doc. Further configuration changes are needed to indicate that and will be tackled in a later guide.
When creating relationship tuples for OpenFGA make sure to use unique ids for each object and user within your application domain. We are using first names and simple ids to just illustrate an easy-to-follow example.
Advanced object to object relationships
Object to object can be used for more advanced use case, such as entitlements. An example use case is to allow subscribers to be entitled to different plans.
01. Create authorization model with object to object relationships
To do this, the authorization model will have two types - feature and plan.
- DSL
- JSON
model
schema 1.1
type user
type feature
relations
define associated_plan: [plan]
define access: [user] or subscriber_member from associated_plan
type plan
relations
define subscriber_member: [user]
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "feature",
"relations": {
"associated_plan": {
"this": {}
},
"access": {
"union": {
"child": [
{
"this": {}
},
{
"tupleToUserset": {
"tupleset": {
"relation": "associated_plan"
},
"computedUserset": {
"relation": "subscriber_member"
}
}
}
]
}
}
},
"metadata": {
"relations": {
"associated_plan": {
"directly_related_user_types": [
{
"type": "plan"
}
]
},
"access": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
},
{
"type": "plan",
"relations": {
"subscriber_member": {
"this": {}
}
},
"metadata": {
"relations": {
"subscriber_member": {
"directly_related_user_types": [
{
"type": "user"
}
]
}
}
}
}
]
}
Type feature
has two relations, associated_plan and access. Relation associated_plan
allows associating plans with features while access
defines who can access the feature. In our case, the access can be achieved either from
- direct relationship via direct relationship type restrictions.
or
this
- object to object relationship where a user can access because it is a subscriber_member of a particular plan AND that plan is associated with the feature.
Here, we define plan
as the user of object feature
with relationship associated_plan
rather than defining feature
as the user of object plan
with relationship feature
. The reason we choose the former is that we want to describe our system in the following plain language:
- A user can access a feature in a plan if they are a subscriber member of a plan that is the associated plan of a feature.
This will give us a flow of user->organization->plan->feature and allows us to answer the question of whether user can access a feature rather than whether user is subscriber of a plan.
02. Adding relationship tuples
To realize the relationship, we will need to add the following relationship tuples.
- Node.js
- Go
- .NET
- Python
- Java
- curl
- CLI
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
await fgaClient.write({
writes: [
// make anne as subscriber_member for plan:advanced
{"_description":"make anne as subscriber_member for plan:advanced","user":"user:anne","relation":"subscriber_member","object":"plan:advanced"},
// The advanced plan is associated with the data preview feature
{"_description":"The advanced plan is associated with the data preview feature","user":"plan:advanced","relation":"associated_plan","object":"feature:data_preview"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientWriteOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientWriteRequest{
Writes: []ClientTupleKey{
{
// make anne as subscriber_member for plan:advanced
User: "user:anne",
Relation: "subscriber_member",
Object: "plan:advanced",
}, {
// The advanced plan is associated with the data preview feature
User: "plan:advanced",
Relation: "associated_plan",
Object: "feature:data_preview",
},
},
}
data, err := fgaClient.Write(context.Background()).
Body(body).
Options(options).
Execute()
if err != nil {
// .. Handle error
}
_ = data // use the response
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientWriteOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientWriteRequest() {
Writes = new List<ClientTupleKey>() {
// make anne as subscriber_member for plan:advanced
new() {
User = "user:anne",
Relation = "subscriber_member",
Object = "plan:advanced"
},
// The advanced plan is associated with the data preview feature
new() {
User = "plan:advanced",
Relation = "associated_plan",
Object = "feature:data_preview"
}
},
};
var response = await fgaClient.Write(body, options);
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientWriteRequest(
writes=[
ClientTuple(
# make anne as subscriber_member for plan:advanced
user="user:anne",
relation="subscriber_member",
object="plan:advanced",
),
ClientTuple(
# The advanced plan is associated with the data preview feature
user="plan:advanced",
relation="associated_plan",
object="feature:data_preview",
),
],
)
response = await fga_client.write(body, options)
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientWriteOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientWriteRequest()
.writes(List.of(
// make anne as subscriber_member for plan:advanced
new ClientTupleKey()
.user("user:anne")
.relation("subscriber_member")
._object("plan:advanced"),
// The advanced plan is associated with the data preview feature
new ClientTupleKey()
.user("plan:advanced")
.relation("associated_plan")
._object("feature:data_preview")
));
var response = fgaClient.write(body, options).get();
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"writes": { "tuple_keys" : [{"_description":"make anne as subscriber_member for plan:advanced","user":"user:anne","relation":"subscriber_member","object":"plan:advanced"},{"_description":"The advanced plan is associated with the data preview feature","user":"plan:advanced","relation":"associated_plan","object":"feature:data_preview"}] }, "authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"}'
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga tuple write --store-id=${FGA_STORE_ID} --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne subscriber_member plan:advanced
fga tuple write --store-id=${FGA_STORE_ID} --model-id=01HVMMBCMGZNT3SED4Z17ECXCA plan:advanced associated_plan feature:data_preview
write([
// make anne as subscriber_member for plan:advanced
{
"user":"user:anne",
"relation":"subscriber_member",
"object":"plan:advanced"
},
// The advanced plan is associated with the data preview feature
{
"user":"plan:advanced",
"relation":"associated_plan",
"object":"feature:data_preview"
}
], authorization_model_id="01HVMMBCMGZNT3SED4Z17ECXCA")
03. Check to see if access is allowed without direct relationship
To validate that the authorization model and relationship tuples are correct, we can ask the question:
- Node.js
- Go
- .NET
- Python
- Java
- CLI
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'access',
object: 'feature:data_preview',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientCheckOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientCheckRequest{
User: "user:anne",
Relation: "access",
Object: "feature:data_preview",
}
data, err := fgaClient.Check(context.Background()).
Body(body).
Options(options).
Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientCheckOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientCheckRequest {
User = "user:anne",
Relation = "access",
Object = "feature:data_preview",
};
var response = await fgaClient.Check(body, options);
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientCheckRequest(
user="user:anne",
relation="access",
object="feature:data_preview",
)
response = await fga_client.check(body, options)
# response.allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientCheckOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientCheckRequest()
.user("user:anne")
.relation("access")
._object("feature:data_preview");
var response = fgaClient.check(body, options).get();
// response.getAllowed() = true
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga query check --store-id=$FGA_STORE_ID --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne access feature:data_preview
# Response: {"allowed":true}
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA", "tuple_key":{"user":"user:anne","relation":"access","object":"feature:data_preview"}}'
# Response: {"allowed":true}
check(
user = "user:anne", // check if the user `user:anne`
relation = "access", // has an `access` relation
object = "feature:data_preview", // with the object `feature:data_preview`
authorization_id = "01HVMMBCMGZNT3SED4Z17ECXCA"
);
Reply: true
We see that anne
is allowed to access
feature:data_preview
without requiring direct relationship.
04. Disassociating plan from feature
At any point in time, plan:advanced
may be disassociated from feature:data_preview
.
- Node.js
- Go
- .NET
- Python
- Java
- curl
- CLI
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
await fgaClient.write({
deletes: [
// Remove advanced plan from data preview feature
{ user: 'plan:advanced', relation: 'associated_plan', object: 'feature:data_preview'}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientWriteOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientWriteRequest{
Deletes: []ClientTupleKeyWithoutCondition{
{
// Remove advanced plan from data preview feature
User: "plan:advanced",
Relation: "associated_plan",
Object: "feature:data_preview",
},
},
}
data, err := fgaClient.Write(context.Background()).
Body(body).
Options(options).
Execute()
if err != nil {
// .. Handle error
}
_ = data // use the response
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientWriteOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientWriteRequest() {
Deletes = new List<ClientTupleKeyWithoutCondition>() {
// Remove advanced plan from data preview feature
new() { User = "plan:advanced", Relation = "associated_plan", Object = "feature:data_preview" }
},
};
var response = await fgaClient.Write(body, options);
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientWriteRequest(
deletes=[
ClientTuple(
# Remove advanced plan from data preview feature
user="plan:advanced",
relation="associated_plan",
object="feature:data_preview",
),
],
)
response = await fga_client.write(body, options)
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientWriteOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientWriteRequest()
.deletes(List.of(
// Remove advanced plan from data preview feature
new ClientTupleKey()
.user("plan:advanced")
.relation("associated_plan")
._object("feature:data_preview")
));
var response = fgaClient.write(body, options).get();
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"deletes": { "tuple_keys" : [{"_description":"Remove advanced plan from data preview feature","user":"plan:advanced","relation":"associated_plan","object":"feature:data_preview"}] }, "authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"}'
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga tuple delete --store-id=${FGA_STORE_ID} plan:advanced associated_plan feature:data_preview
delete([
// Remove advanced plan from data preview feature
{
"user":"plan:advanced",
"relation":"associated_plan",
"object":"feature:data_preview"
}
], authorization_model_id="01HVMMBCMGZNT3SED4Z17ECXCA")
When this is the case, anne
will no longer have access
to feature:data_preview
even though she is still a subscriber_member
of plan:advanced
.
- Node.js
- Go
- .NET
- Python
- Java
- CLI
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'access',
object: 'feature:data_preview',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});
// allowed = false
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientCheckOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientCheckRequest{
User: "user:anne",
Relation: "access",
Object: "feature:data_preview",
}
data, err := fgaClient.Check(context.Background()).
Body(body).
Options(options).
Execute()
// data = { allowed: false }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientCheckOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientCheckRequest {
User = "user:anne",
Relation = "access",
Object = "feature:data_preview",
};
var response = await fgaClient.Check(body, options);
// response.Allowed = false
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientCheckRequest(
user="user:anne",
relation="access",
object="feature:data_preview",
)
response = await fga_client.check(body, options)
# response.allowed = false
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientCheckOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientCheckRequest()
.user("user:anne")
.relation("access")
._object("feature:data_preview");
var response = fgaClient.check(body, options).get();
// response.getAllowed() = true
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga query check --store-id=$FGA_STORE_ID --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne access feature:data_preview
# Response: {"allowed":false}
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA", "tuple_key":{"user":"user:anne","relation":"access","object":"feature:data_preview"}}'
# Response: {"allowed":false}
check(
user = "user:anne", // check if the user `user:anne`
relation = "access", // has an `access` relation
object = "feature:data_preview", // with the object `feature:data_preview`
authorization_id = "01HVMMBCMGZNT3SED4Z17ECXCA"
);
Reply: false
- Node.js
- Go
- .NET
- Python
- Java
- CLI
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});
// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'subscriber_member',
object: 'plan:advanced',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
"os"
. "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"), // required, e.g. https://api.fga.example
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional, can be overridden per request
})
if err != nil {
// .. Handle error
}
}
options := ClientCheckOptions{
AuthorizationModelId: PtrString("01HVMMBCMGZNT3SED4Z17ECXCA"),
}
body := ClientCheckRequest{
User: "user:anne",
Relation: "subscriber_member",
Object: "plan:advanced",
}
data, err := fgaClient.Check(context.Background()).
Body(body).
Options(options).
Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
namespace Example;
class Example {
public static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"), ?? "http://localhost:8080", // required, e.g. https://api.fga.example
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional, can be overridden per request
};
var fgaClient = new OpenFgaClient(configuration);
}
}
var options = new ClientCheckOptions {
AuthorizationModelId = "01HVMMBCMGZNT3SED4Z17ECXCA",
};
var body = new ClientCheckRequest {
User = "user:anne",
Relation = "subscriber_member",
Object = "plan:advanced",
};
var response = await fgaClient.Check(body, options);
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import asyncio
import os
import json
from openfga_sdk.client import ClientConfiguration, OpenFgaClient
async def main():
configuration = ClientConfiguration(
api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example
store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request
)
# Enter a context with an instance of the OpenFgaClient
async with OpenFgaClient(configuration) as fga_client:
api_response = await fga_client.read_authorization_models()
await fga_client.close()
asyncio.run(main())
options = {
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}
body = ClientCheckRequest(
user="user:anne",
relation="subscriber_member",
object="plan:advanced",
)
response = await fga_client.check(body, options)
# response.allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL")) // If not specified, will default to "https://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_AUTHORIZATION_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
}
}
var options = new ClientCheckOptions()
.authorizationModelId("01HVMMBCMGZNT3SED4Z17ECXCA");
var body = new ClientCheckRequest()
.user("user:anne")
.relation("subscriber_member")
._object("plan:advanced");
var response = fgaClient.check(body, options).get();
// response.getAllowed() = true
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
fga query check --store-id=$FGA_STORE_ID --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne subscriber_member plan:advanced
# Response: {"allowed":true}
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_API_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA", "tuple_key":{"user":"user:anne","relation":"subscriber_member","object":"plan:advanced"}}'
# Response: {"allowed":true}
check(
user = "user:anne", // check if the user `user:anne`
relation = "subscriber_member", // has an `subscriber_member` relation
object = "plan:advanced", // with the object `plan:advanced`
authorization_id = "01HVMMBCMGZNT3SED4Z17ECXCA"
);
Reply: true