Skip to main content

Update Relationship Tuples

This is an introduction to adding and deleting relationship tuples.

Before you start

  1. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN.
  2. You have installed the SDK.
  3. You have configured the authorization model.
  4. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables.

Step by step

Assume that you want to add user user:anne to have relationship reader with object document:Z

{
user: 'user:anne',
relation: 'reader',
object: 'document:Z'
}

01. Configure the OpenFGA API client

Before calling the write API, you will need to configure the API client.

// 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
});

02. Calling write API to add new relationship tuples

To add the relationship tuples, we can invoke the write API.


await fgaClient.write({
writes: [
{"user":"user:anne","relation":"reader","object":"document:Z"}
],
}, {
authorizationModelId: "01HVMMBCMGZNT3SED4Z17ECXCA"
});

03. Calling write API to delete relationship tuples

To delete relationship tuples, we can invoke the write API.

Assume that you want to delete user user:anne's reader relationship with object document:Z

{
user: 'user:anne',
relation: 'reader',
object: 'document:Z'
}

await fgaClient.write({
deletes: [
{ user: 'user:anne', relation: 'reader', object: 'document:Z'}
],
}, {
authorizationModelId: "01HVMMBCMGZNT3SED4Z17ECXCA"
});

04. Writing and deleting relationship tuples in the same request

You can combine both writes and deletes in a single transactional API request. This is useful when you need to update multiple relationships atomically. All operations in the request will either succeed together or fail together.

The Write API allows you to send up to 100 unique tuples in the request. (This limit applies to the sum of both writes and deletes in that request).

For example, you might want to remove user:anne as a writer of document:Z while simultaneously updating user:anne as an reader of document:Z:


await fgaClient.write({
writes: [
{"user":"user:anne","relation":"reader","object":"document:Z"}
],
deletes: [
{ user: 'user:anne', relation: 'writer', object: 'document:Z'}
],
}, {
authorizationModelId: "01HVMMBCMGZNT3SED4Z17ECXCA"
});

This approach ensures that both operations succeed or fail together, maintaining transactional data consistency.

note

When using the Write API, you cannot include the same tuple (same user, relation, and object) in the writes or deletes arrays within a single request. The API will return an error with code cannot_allow_duplicate_tuples_in_one_request if detected.

05. Ignoring duplicate or missing tuples

Sometimes you might need to write a tuple that already exists, which would normally cause the whole request to fail. You can use the on_duplicate: "ignore" parameter to handle this gracefully.

This is particularly useful for high-volume data imports, migrations, or ensuring certain permissions exist without complex error handling logic.

For example, if you want to ensure user:anne has reader access to document:Z without worrying about whether the relationship already exists in OpenFGA:

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": [
{
"user": "user:anne",
"relation": "reader",
"object": "document:Z"
}
],
"on_duplicate": "ignore"
},
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}'
caution

At the moment, this feature is only available on the API (v1.10.0). Supported SDKs will follow shortly after.

Similarly, you can use on_missing: "ignore" when deleting tuples that might not exist.

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": [
{
"user": "user:anne",
"relation": "writer",
"object": "document:Z"
}
],
"on_missing": "ignore"
},
"authorization_model_id": "01HVMMBCMGZNT3SED4Z17ECXCA"
}'

The behavior of on_duplicate: "ignore" is more nuanced for tuples with conditions.

  • Identical Tuples: If a tuple in the request is identical to an existing tuple (same user, relation, object, condition name, and condition context), it will be safely ignored.
  • Conflicting Tuples: If a tuple key (user, relation, object) matches an existing tuple, but the condition name or parameters are different, this is a conflict. The write attempt will be rejected, and the entire transaction will fail with a 409 Conflict error.
Write API

Learn more about the Write API options.

Managing User Access

Learn about how to give a user access to a particular object.

Managing Group Access

Learn about how to give a group of users access to a particular object.