Migrating Relations
In the lifecycle of software development, you will need to make updates or changes to the authorization model. In this guide, you will learn best practices for changing your existing authorization model. With these recommendations, you will minimize downtime and ensure your relationship models stay up to date.
Before You Start
This guide assumes you are familiar with the following 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
- Intersection Operator: the intersection operator can be used to indicate a relationship exists if the user is in all the sets of users
Step By Step
The document below is an example of a relational authorization model. In this model, you can assign users to the editor
relation. The editor
relation has write privileges that regular users do not.
In this scenario, you will migrate the following model:
- DSL
- JSON
model
schema 1.1
type document
relations
define editor:
define can_edit: editor
type user
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "document",
"relations": {
"editor": {
"this": {}
},
"can_edit": {
"computedUserset": {
"object": "",
"relation": "editor"
}
}
}
},
{
"type": "user"
}
]
}
There are existing relationship tuples associated with editor relation.
[
{
"user": "user:anne",
"relation": "editor",
"object": "document:roadmap",
},
{
"user": "user:charles",
"relation": "editor",
"object": "document:roadmap",
},
]
This is the authorization model that you will want to migrate to:
- DSL
- JSON
model
schema 1.1
type document
relations
define writer:
define can_write: writer
type user
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "document",
"relations": {
"writer": {
"this": {}
},
"can_write": {
"computedUserset": {
"object": "",
"relation": "writer"
}
}
}
},
{
"type": "user"
}
]
}
01. Create A Backwards Compatible Model
To avoid service disruption, you will create a backwards compatible model. The backwards compatible model ensures the existing relationship tuple will still work.
In the example below, user:Anne
still has write privileges to the document:roadmap
resource.
- DSL
- JSON
model
schema 1.1
type document
relations
define editor:
define writer: or editor
define can_write: writer
define can_edit: writer
type user
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "document",
"relations": {
"editor": {
"this": {}
},
"writer": {
"union": {
"child": [
{
"this": {}
},
{
"computedUserset": {
"relation": "editor"
}
}
]
}
},
"can_write": {
"computedUserset": {
"object": "",
"relation": "writer"
}
},
"can_edit": {
"computedUserset": {
"object": "",
"relation": "writer"
}
}
}
},
{
"type": "user"
}
]
}
Test the can_edit
definition. It should produce a value of true
.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Run a check
const { allowed } = await fgaClient.check({
authorization_model_id: '1uHxCSuTP0VKPYSnkq1pbb1jeZw',
tuple_key: {
user: 'user:anne',
relation: 'can_write',
object: 'document:roadmap',
},
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequest{
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw"),
TupleKey: fgaSdk.TupleKey{
User: "user:anne",
Relation: "can_write",
Object: "document:roadmap",
},
}
data, response, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check{TupleKey = new CheckRequest(new TupleKey() {
User = "user:anne",
Relation = "can_write",
Object = "document:roadmap"
}, AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"};
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.check_request import CheckRequest
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.contextual_tuple_keys import ContextualTupleKeys
# Run a check
async def check():
body = CheckRequest(
tuple_key=TupleKey(
user="user:anne",
relation="can_write",
object="document:roadmap",
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
response = await fga_client_instance.check(body)
# response.allowed = true
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "1uHxCSuTP0VKPYSnkq1pbb1jeZw", "tuple_key":{"user":"user:anne","relation":"can_write","object":"document:roadmap"}}'
# Response: {"allowed":true}
check(
user = "user:anne", // check if the user `user:anne`
relation = "can_write", // has an `can_write` relation
object = "document:roadmap", // with the object `document:roadmap`
authorization_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
);
Reply: true
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Run a check
const { allowed } = await fgaClient.check({
authorization_model_id: '1uHxCSuTP0VKPYSnkq1pbb1jeZw',
tuple_key: {
user: 'user:anne',
relation: 'can_edit',
object: 'document:roadmap',
},
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequest{
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw"),
TupleKey: fgaSdk.TupleKey{
User: "user:anne",
Relation: "can_edit",
Object: "document:roadmap",
},
}
data, response, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check{TupleKey = new CheckRequest(new TupleKey() {
User = "user:anne",
Relation = "can_edit",
Object = "document:roadmap"
}, AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"};
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.check_request import CheckRequest
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.contextual_tuple_keys import ContextualTupleKeys
# Run a check
async def check():
body = CheckRequest(
tuple_key=TupleKey(
user="user:anne",
relation="can_edit",
object="document:roadmap",
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
response = await fga_client_instance.check(body)
# response.allowed = true
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "1uHxCSuTP0VKPYSnkq1pbb1jeZw", "tuple_key":{"user":"user:anne","relation":"can_edit","object":"document:roadmap"}}'
# Response: {"allowed":true}
check(
user = "user:anne", // check if the user `user:anne`
relation = "can_edit", // has an `can_edit` relation
object = "document:roadmap", // with the object `document:roadmap`
authorization_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
);
Reply: true
02. Create a New Relationship Tuple
Now that you have a backwards compatible model, you can create new relationship tuples with a new relation.
In this example, you will add Bethany to the writer
relationship.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
await fgaClient.write({
writes: {
tuple_keys: [
// Bethany assigned writer instead of editor
{ user: 'user:bethany', relation: 'writer', object: 'document:roadmap'}
]
},
authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.WriteRequest{
Writes: &fgaSdk.TupleKeys{
TupleKeys: []fgaSdk.TupleKey {
{
// Bethany assigned writer instead of editor
User: fgaSdk.PtrString("user:bethany"),
Relation: fgaSdk.PtrString("writer"),
Object: fgaSdk.PtrString("document:roadmap"),
},
},
},
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw")}
_, response, err := fgaClient.OpenFgaApi.Write(context.Background()).Body(body).Execute()
if err != nil {
// .. Handle error
}
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
await fgaClient.Write(new WriteRequest{
Writes = new TupleKeys(new List<TupleKey>() {
// Bethany assigned writer instead of editor
new() { User = "user:bethany", Relation = "writer", Object = "document:roadmap" }
}),
AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.tuple_keys import TupleKeys
# from openfga_sdk.models.write_request import WriteRequest
async def write():
body = WriteRequest(
writes=TupleKeys(
tuple_keys=[
TupleKey(
# Bethany assigned writer instead of editor
user="user:bethany",
relation="writer",
object="document:roadmap",
),
],
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
await fga_client_instance.write(body)
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"writes": { "tuple_keys" : [{"user":"user:bethany","relation":"writer","object":"document:roadmap"}] }, authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"}'
write([
// Bethany assigned writer instead of editor
{
"user":"user:bethany",
"relation":"writer",
"object":"document:roadmap"
}
], authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw")
Run a check in the API for Bethany to ensure correct access.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Run a check
const { allowed } = await fgaClient.check({
authorization_model_id: '1uHxCSuTP0VKPYSnkq1pbb1jeZw',
tuple_key: {
user: 'user:bethany',
relation: 'can_write',
object: 'document:roadmap',
},
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequest{
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw"),
TupleKey: fgaSdk.TupleKey{
User: "user:bethany",
Relation: "can_write",
Object: "document:roadmap",
},
}
data, response, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check{TupleKey = new CheckRequest(new TupleKey() {
User = "user:bethany",
Relation = "can_write",
Object = "document:roadmap"
}, AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"};
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.check_request import CheckRequest
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.contextual_tuple_keys import ContextualTupleKeys
# Run a check
async def check():
body = CheckRequest(
tuple_key=TupleKey(
user="user:bethany",
relation="can_write",
object="document:roadmap",
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
response = await fga_client_instance.check(body)
# response.allowed = true
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "1uHxCSuTP0VKPYSnkq1pbb1jeZw", "tuple_key":{"user":"user:bethany","relation":"can_write","object":"document:roadmap"}}'
# Response: {"allowed":true}
check(
user = "user:bethany", // check if the user `user:bethany`
relation = "can_write", // has an `can_write` relation
object = "document:roadmap", // with the object `document:roadmap`
authorization_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
);
Reply: true
03. Migrate The Existing Relationship Tuples
Next, migrate the existing relationship tuples. The new relation makes this definition obsolete.
Use the read
API to lookup all relationship tuples.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Execute a read
const { tuples } = await fgaClient.read({});
// tuples = [{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.ReadRequest{}
data, response, err := fgaClient.OpenFgaApi.Read(context.Background()).Body(body).Execute()
// data = { "tuples": [{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}] }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
var response = fgaClient.Read(new ReadRequest());
// data = { "tuples": [{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}] }
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.read_request import ReadRequest
# from openfga_sdk.models.read_response import ReadResponse
# from openfga_sdk.models.tuple_key import TupleKey
async def read():
body = ReadRequest()
response = await fga_client_instance.read(body)
# response = ReadResponse({"tuples":[{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]})
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/read \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" '
# Response: "tuples": {[{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]}
read(
// read all stored tuples
);
Reply: tuples:[{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]
Then filter out the tuples that do not match the object type or relation (in this case, document
and editor
respectively), and update the new tuples with the write
relationship.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
await fgaClient.write({
writes: {
tuple_keys: [
{ user: 'user:anne', relation: 'writer', object: 'document:roadmap'},
{ user: 'user:charles', relation: 'writer', object: 'document:roadmap'}
]
},
authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.WriteRequest{
Writes: &fgaSdk.TupleKeys{
TupleKeys: []fgaSdk.TupleKey {
{
User: fgaSdk.PtrString("user:anne"),
Relation: fgaSdk.PtrString("writer"),
Object: fgaSdk.PtrString("document:roadmap"),
},
{
User: fgaSdk.PtrString("user:charles"),
Relation: fgaSdk.PtrString("writer"),
Object: fgaSdk.PtrString("document:roadmap"),
},
},
},
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw")}
_, response, err := fgaClient.OpenFgaApi.Write(context.Background()).Body(body).Execute()
if err != nil {
// .. Handle error
}
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
await fgaClient.Write(new WriteRequest{
Writes = new TupleKeys(new List<TupleKey>() {
new() { User = "user:anne", Relation = "writer", Object = "document:roadmap" },
new() { User = "user:charles", Relation = "writer", Object = "document:roadmap" }
}),
AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.tuple_keys import TupleKeys
# from openfga_sdk.models.write_request import WriteRequest
async def write():
body = WriteRequest(
writes=TupleKeys(
tuple_keys=[
TupleKey(
user="user:anne",
relation="writer",
object="document:roadmap",
),
TupleKey(
user="user:charles",
relation="writer",
object="document:roadmap",
),
],
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
await fga_client_instance.write(body)
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"writes": { "tuple_keys" : [{"user":"user:anne","relation":"writer","object":"document:roadmap"},{"user":"user:charles","relation":"writer","object":"document:roadmap"}] }, authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"}'
write([
{
"user":"user:anne",
"relation":"writer",
"object":"document:roadmap"
},
{
"user":"user:charles",
"relation":"writer",
"object":"document:roadmap"
}
], authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw")
Finally, remove the old relationship tuples.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
await fgaClient.write({
deletes: {
tuple_keys : [
{ user: 'user:anne', relation: 'editor', object: 'document:roadmap'},
{ user: 'user:charles', relation: 'editor', object: 'document:roadmap'}
]
},
authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.WriteRequest{
Deletes: &fgaSdk.TupleKeys{
TupleKeys: []fgaSdk.TupleKey {
{
User: fgaSdk.PtrString("user:anne"),
Relation: fgaSdk.PtrString("editor"),
Object: fgaSdk.PtrString("document:roadmap"),
},
{
User: fgaSdk.PtrString("user:charles"),
Relation: fgaSdk.PtrString("editor"),
Object: fgaSdk.PtrString("document:roadmap"),
},
},
},
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw")}
_, response, err := fgaClient.OpenFgaApi.Write(context.Background()).Body(body).Execute()
if err != nil {
// .. Handle error
}
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
await fgaClient.Write(new WriteRequest{
Deletes = new TupleKeys(new List<TupleKey>() {
new() { User = "user:anne", Relation = "editor", Object = "document:roadmap" },
new() { User = "user:charles", Relation = "editor", Object = "document:roadmap" }
}),
AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
});
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.tuple_keys import TupleKeys
# from openfga_sdk.models.write_request import WriteRequest
async def write():
body = WriteRequest(
deletes=TupleKeys(
tuple_keys=[
TupleKey(
user="user:anne",
relation="editor",
object="document:roadmap",
),
TupleKey(
user="user:charles",
relation="editor",
object="document:roadmap",
),
],
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
await fga_client_instance.write(body)
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/write \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"deletes": { "tuple_keys" : [{"user":"user:anne","relation":"editor","object":"document:roadmap"},{"user":"user:charles","relation":"editor","object":"document:roadmap"}] }, authorization_model_id: "1uHxCSuTP0VKPYSnkq1pbb1jeZw"}'
delete([
{
"user":"user:anne",
"relation":"editor",
"object":"document:roadmap"
},
{
"user":"user:charles",
"relation":"editor",
"object":"document:roadmap"
}
], authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw")
Perform a write
operation before a delete
operation to ensure Anne still has access.
Confirm the tuples are correct by running a check on the user.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Run a check
const { allowed } = await fgaClient.check({
authorization_model_id: '1uHxCSuTP0VKPYSnkq1pbb1jeZw',
tuple_key: {
user: 'user:anne',
relation: 'can_write',
object: 'document:roadmap',
},
});
// allowed = true
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequest{
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw"),
TupleKey: fgaSdk.TupleKey{
User: "user:anne",
Relation: "can_write",
Object: "document:roadmap",
},
}
data, response, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: true }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check{TupleKey = new CheckRequest(new TupleKey() {
User = "user:anne",
Relation = "can_write",
Object = "document:roadmap"
}, AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"};
// response.Allowed = true
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.check_request import CheckRequest
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.contextual_tuple_keys import ContextualTupleKeys
# Run a check
async def check():
body = CheckRequest(
tuple_key=TupleKey(
user="user:anne",
relation="can_write",
object="document:roadmap",
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
response = await fga_client_instance.check(body)
# response.allowed = true
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "1uHxCSuTP0VKPYSnkq1pbb1jeZw", "tuple_key":{"user":"user:anne","relation":"can_write","object":"document:roadmap"}}'
# Response: {"allowed":true}
check(
user = "user:anne", // check if the user `user:anne`
relation = "can_write", // has an `can_write` relation
object = "document:roadmap", // with the object `document:roadmap`
authorization_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
);
Reply: true
The old relationship tuple no longer exists.
- Node.js
- Go
- .NET
- Python
- curl
- Pseudocode
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaApi } = require('@openfga/sdk');
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaApi({
apiScheme: process.env.FGA_API_SCHEME, // Either "http" or "https", defaults to "https"
apiHost: process.env.FGA_API_HOST, // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
storeId: process.env.FGA_STORE_ID, // Either "http" or "https", defaults to "https"
});
// Run a check
const { allowed } = await fgaClient.check({
authorization_model_id: '1uHxCSuTP0VKPYSnkq1pbb1jeZw',
tuple_key: {
user: 'user:anne',
relation: 'editor',
object: 'document:roadmap',
},
});
// allowed = false
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import (
fgaSdk "github.com/openfga/go-sdk"
"os"
)
func main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
configuration, err := fgaSdk.NewConfiguration(fgaSdk.UserConfiguration{
ApiScheme: os.Getenv("FGA_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost: os.Getenv("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId: os.Getenv("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
})
if err != nil {
// .. Handle error
}
fgaClient := fgaSdk.NewAPIClient(configuration)
}
body := fgaSdk.CheckRequest{
AuthorizationModelId: fgaSdk.PtrString("1uHxCSuTP0VKPYSnkq1pbb1jeZw"),
TupleKey: fgaSdk.TupleKey{
User: "user:anne",
Relation: "editor",
Object: "document:roadmap",
},
}
data, response, err := fgaClient.OpenFgaApi.Check(context.Background()).Body(body).Execute()
// data = { allowed: false }
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
using OpenFga.Sdk.Api;
using OpenFga.Sdk.Configuration;
using Environment = System.Environment;
namespace ExampleApp;
class MyProgram {
static async Task Main() {
// Initialize the SDK with no auth - see "How to setup SDK client" for more options
var configuration = new Configuration() {
ApiScheme = Environment.GetEnvironmentVariable("FGA_API_SCHEME"), // Either "http" or "https", defaults to "https"
ApiHost = Environment.GetEnvironmentVariable("FGA_API_HOST"), // required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
};
var fgaClient = new OpenFgaApi(configuration);
}
}
// Run a check
var response = await fgaClient.Check{TupleKey = new CheckRequest(new TupleKey() {
User = "user:anne",
Relation = "editor",
Object = "document:roadmap"
}, AuthorizationModelId = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"};
// response.Allowed = false
Initialize the SDK
# ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
import os
import json
import openfga_sdk
from openfga_sdk.api import open_fga_api
configuration = openfga_sdk.Configuration(
api_scheme = os.environ.get('FGA_API_SCHEME'), # Either "http" or "https", defaults to "https"
api_host = os.environ.get('FGA_API_HOST'), # required, define without the scheme (e.g. api.openfga.example instead of https://api.openfga.example)
store_id = os.environ.get('FGA_STORE_ID') # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods
)
# Create an instance of the API class
fga_client_instance = open_fga_api.OpenFgaApi(openfga_sdk.ApiClient(configuration))
# from openfga_sdk.models.check_request import CheckRequest
# from openfga_sdk.models.tuple_key import TupleKey
# from openfga_sdk.models.contextual_tuple_keys import ContextualTupleKeys
# Run a check
async def check():
body = CheckRequest(
tuple_key=TupleKey(
user="user:anne",
relation="editor",
object="document:roadmap",
),
authorization_model_id="1uHxCSuTP0VKPYSnkq1pbb1jeZw",
)
response = await fga_client_instance.check(body)
# response.allowed = false
Get the Bearer Token and set up the FGA_API_URL environment variable
Set FGA_API_URL according to the service you are using
curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \
-H "Authorization: Bearer $FGA_BEARER_TOKEN" \ # Not needed if service does not require authorization
-H "content-type: application/json" \
-d '{"authorization_model_id": "1uHxCSuTP0VKPYSnkq1pbb1jeZw", "tuple_key":{"user":"user:anne","relation":"editor","object":"document:roadmap"}}'
# Response: {"allowed":false}
check(
user = "user:anne", // check if the user `user:anne`
relation = "editor", // has an `editor` relation
object = "document:roadmap", // with the object `document:roadmap`
authorization_id = "1uHxCSuTP0VKPYSnkq1pbb1jeZw"
);
Reply: false
04. Remove Obsolete Relationship From The Model
After you remove the previous relationship tuples, update your authorization model to remove the obsolete relation.
- DSL
- JSON
model
schema 1.1
type document
relations
define writer:
define can_write: writer
type user
{
"schema_version": "1.1",
"type_definitions": [
{
"type": "document",
"relations": {
"writer": {
"this": {}
},
"can_write": {
"computedUserset": {
"object": "",
"relation": "writer"
}
}
}
},
{
"type": "user"
}
]
}
Now, the write
API will only accept the new relation name.