Check multiple authorizations in a single request
The BatchCheck API functions nearly identically to Check, but instead of checking a single user-object relationship BatchCheck accepts a list of relationships to check and returns a map containing BatchCheckItem response for each check it received.
An associated correlation_id is required for each check in the batch. This ID is used to correlate a check to the appropriate response. It is a string consisting of only alphanumeric characters or hyphens with a maximum length of 36 characters. This correlation_id is used to map the result of each check to the item which was checked, so it must be unique for each item in the batch. We recommend using a UUID or ULID as the correlation_id, but you can use whatever unique identifier you need as long as it matches this regex pattern: ^[\w\d-]{1,36}$
Note: The maximum number of checks that can be passed in the
BatchCheckAPI is configurable using the environment variable:[OPENFGA_MAX_CHECKS_PER_BATCH_CHECK](https://openfga.dev/docs/getting-started/setup-openfga/configuration#OPENFGA_MAX_CHECKS_PER_BATCH_CHECK). IfBatchCheckis called using the SDK, the SDK can split the batch check requests for you.
For more details on how Check functions, review the docs for /check.
Examples
A BatchCheckRequest
{
"checks": [
{
"tuple_key": {
"object": "document:2021-budget"
"relation": "reader",
"user": "user:anne",
},
"contextual_tuples": {...}
"context": {}
"correlation_id": "01JA8PM3QM7VBPGB8KMPK8SBD5"
},
{
"tuple_key": {
"object": "document:2021-budget"
"relation": "reader",
"user": "user:bob",
},
"contextual_tuples": {...}
"context": {}
"correlation_id": "01JA8PMM6A90NV5ET0F28CYSZQ"
}
]
}
Below is a possible response to the above request. Note that the result map’s keys are the correlation_id values from the checked items in the request:
{
"result": {
"01JA8PMM6A90NV5ET0F28CYSZQ": {
"allowed": false,
"error": {"message": ""}
},
"01JA8PM3QM7VBPGB8KMPK8SBD5": {
"allowed": true,
"error": {"message": ""}
}
}
const { OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional; requests can override this.
});
async function main() {
const body = {
"checks": [
{
"user": "user:anne",
"relation": "reader",
"object": "document:budget",
"correlationId": "budget-reader"
}
]
};
const options = {
"maxBatchSize": 50,
"maxParallelRequests": 10
};
const response = await fgaClient.batchCheck(body, options);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"os"
openfga "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"),
StoreId: os.Getenv("FGA_STORE_ID"),
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional; requests can override this.
})
if err != nil {
panic(err)
}
body := ClientBatchCheckRequest{
Checks: []ClientBatchCheckItem{
ClientBatchCheckItem{
User: "user:anne",
Relation: "reader",
Object: "document:budget",
CorrelationId: "budget-reader",
},
},
}
options := BatchCheckOptions{
MaxBatchSize: openfga.PtrInt32(50),
MaxParallelRequests: openfga.PtrInt32(10),
}
data, err := fgaClient.BatchCheck(context.Background()).Body(body).Options(options).Execute()
if err != nil {
panic(err)
}
_ = data
}using System.Collections.Generic;
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
var fgaClient = new OpenFgaClient(new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional; requests can override this.
});
var body = new ClientBatchCheckRequest {
Checks = new List<ClientBatchCheckItem> {
new ClientBatchCheckItem {
User = "user:anne",
Relation = "reader",
Object = "document:budget",
CorrelationId = "budget-reader",
},
},
};
var options = new ClientBatchCheckOptions {
MaxBatchSize = 50,
MaxParallelRequests = 10,
};
var response = await fgaClient.BatchCheck(body, options);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientBatchCheckItem, ClientBatchCheckRequest, ClientTuple
from openfga_sdk.models import RelationshipCondition
async def main():
configuration = ClientConfiguration(
api_url=os.environ.get("FGA_API_URL"),
store_id=os.environ.get("FGA_STORE_ID"),
authorization_model_id=os.environ.get("FGA_MODEL_ID"), # Optional; requests can override this.
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientBatchCheckRequest(
checks=[
ClientBatchCheckItem(
user="user:anne",
relation="reader",
object="document:budget",
correlation_id="budget-reader",
)
],
)
options = {
}
response = await fga_client.batch_check(body, options)
asyncio.run(main())import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.*;
import dev.openfga.sdk.api.client.model.*;
import dev.openfga.sdk.api.model.*;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL"))
.storeId(System.getenv("FGA_STORE_ID"))
.authorizationModelId(System.getenv("FGA_MODEL_ID")); // Optional; requests can override this.
var fgaClient = new OpenFgaClient(config);
var body = new ClientBatchCheckRequest()
.checks(java.util.Arrays.asList(new ClientBatchCheckItem()
.user("user:anne")
.relation("reader")
._object("document:budget")
.correlationId("budget-reader")));
var options = new ClientBatchCheckOptions()
.maxBatchSize(50)
.maxParallelRequests(10);
var response = fgaClient.batchCheck(body, options).get();
}
}# Set FGA_API_URL to the URL of your OpenFGA server.
# Set FGA_STORE_ID to your store ID.
# These examples use a server with authentication disabled.
# For authenticated servers, see /docs/getting-started/setup-sdk-client.
curl -X POST "$FGA_API_URL/stores/$FGA_STORE_ID/batch-check" \
-H "content-type: application/json" \
-d '{
"authorization_model_id": "'"$FGA_MODEL_ID"'",
"checks": [
{
"tuple_key": {
"user": "user:anne",
"relation": "reader",
"object": "document:budget"
},
"correlation_id": "budget-reader"
}
]
}'{
"result": {
"1cd93d8c-8e45-43c6-9a15-cbb3c7f394bc": {
"allowed": true,
"error": {
"message": ""
}
}
}
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthenticated",
"message": "unauthenticated"
}{
"code": "forbidden",
"message": "the principal is not authorized to perform the action"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "internal_error",
"message": "Internal Server Error"
}Path Parameters
Body
1Show child attributes
Show child attributes
"01G5JAVJ41T49E9TT3SKVS7X1J"
Controls the consistency preferences when calling the query APIs.
- UNSPECIFIED: Default if not set. Behavior will be the same as MINIMIZE_LATENCY.
- MINIMIZE_LATENCY: Minimize latency at the potential expense of lower consistency.
- HIGHER_CONSISTENCY: Prefer higher consistency, at the potential expense of increased latency.
UNSPECIFIED, MINIMIZE_LATENCY, HIGHER_CONSISTENCY "MINIMIZE_LATENCY"
Response
A successful response.
Map keys are the correlation_id values from the BatchCheckItems in the request.
Show child attributes
Show child attributes
{
"1cd93d8c-8e45-43c6-9a15-cbb3c7f394bc": {
"allowed": true,
"error": { "message": "" }
}
}
Was this page helpful?
const { OpenFgaClient, ConsistencyPreference } = require('@openfga/sdk');
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL,
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional; requests can override this.
});
async function main() {
const body = {
"checks": [
{
"user": "user:anne",
"relation": "reader",
"object": "document:budget",
"correlationId": "budget-reader"
}
]
};
const options = {
"maxBatchSize": 50,
"maxParallelRequests": 10
};
const response = await fgaClient.batchCheck(body, options);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});package main
import (
"context"
"os"
openfga "github.com/openfga/go-sdk"
. "github.com/openfga/go-sdk/client"
)
func main() {
fgaClient, err := NewSdkClient(&ClientConfiguration{
ApiUrl: os.Getenv("FGA_API_URL"),
StoreId: os.Getenv("FGA_STORE_ID"),
AuthorizationModelId: os.Getenv("FGA_MODEL_ID"), // Optional; requests can override this.
})
if err != nil {
panic(err)
}
body := ClientBatchCheckRequest{
Checks: []ClientBatchCheckItem{
ClientBatchCheckItem{
User: "user:anne",
Relation: "reader",
Object: "document:budget",
CorrelationId: "budget-reader",
},
},
}
options := BatchCheckOptions{
MaxBatchSize: openfga.PtrInt32(50),
MaxParallelRequests: openfga.PtrInt32(10),
}
data, err := fgaClient.BatchCheck(context.Background()).Body(body).Options(options).Execute()
if err != nil {
panic(err)
}
_ = data
}using System.Collections.Generic;
using OpenFga.Sdk.Client;
using OpenFga.Sdk.Client.Model;
using OpenFga.Sdk.Model;
using Environment = System.Environment;
var fgaClient = new OpenFgaClient(new ClientConfiguration() {
ApiUrl = Environment.GetEnvironmentVariable("FGA_API_URL"),
StoreId = Environment.GetEnvironmentVariable("FGA_STORE_ID"),
AuthorizationModelId = Environment.GetEnvironmentVariable("FGA_MODEL_ID"), // Optional; requests can override this.
});
var body = new ClientBatchCheckRequest {
Checks = new List<ClientBatchCheckItem> {
new ClientBatchCheckItem {
User = "user:anne",
Relation = "reader",
Object = "document:budget",
CorrelationId = "budget-reader",
},
},
};
var options = new ClientBatchCheckOptions {
MaxBatchSize = 50,
MaxParallelRequests = 10,
};
var response = await fgaClient.BatchCheck(body, options);import asyncio
import os
from openfga_sdk.client import OpenFgaClient, ClientConfiguration
from openfga_sdk.client.models import ClientBatchCheckItem, ClientBatchCheckRequest, ClientTuple
from openfga_sdk.models import RelationshipCondition
async def main():
configuration = ClientConfiguration(
api_url=os.environ.get("FGA_API_URL"),
store_id=os.environ.get("FGA_STORE_ID"),
authorization_model_id=os.environ.get("FGA_MODEL_ID"), # Optional; requests can override this.
)
async with OpenFgaClient(configuration) as fga_client:
body = ClientBatchCheckRequest(
checks=[
ClientBatchCheckItem(
user="user:anne",
relation="reader",
object="document:budget",
correlation_id="budget-reader",
)
],
)
options = {
}
response = await fga_client.batch_check(body, options)
asyncio.run(main())import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.*;
import dev.openfga.sdk.api.client.model.*;
import dev.openfga.sdk.api.model.*;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
public class Example {
public static void main(String[] args) throws Exception {
var config = new ClientConfiguration()
.apiUrl(System.getenv("FGA_API_URL"))
.storeId(System.getenv("FGA_STORE_ID"))
.authorizationModelId(System.getenv("FGA_MODEL_ID")); // Optional; requests can override this.
var fgaClient = new OpenFgaClient(config);
var body = new ClientBatchCheckRequest()
.checks(java.util.Arrays.asList(new ClientBatchCheckItem()
.user("user:anne")
.relation("reader")
._object("document:budget")
.correlationId("budget-reader")));
var options = new ClientBatchCheckOptions()
.maxBatchSize(50)
.maxParallelRequests(10);
var response = fgaClient.batchCheck(body, options).get();
}
}# Set FGA_API_URL to the URL of your OpenFGA server.
# Set FGA_STORE_ID to your store ID.
# These examples use a server with authentication disabled.
# For authenticated servers, see /docs/getting-started/setup-sdk-client.
curl -X POST "$FGA_API_URL/stores/$FGA_STORE_ID/batch-check" \
-H "content-type: application/json" \
-d '{
"authorization_model_id": "'"$FGA_MODEL_ID"'",
"checks": [
{
"tuple_key": {
"user": "user:anne",
"relation": "reader",
"object": "document:budget"
},
"correlation_id": "budget-reader"
}
]
}'{
"result": {
"1cd93d8c-8e45-43c6-9a15-cbb3c7f394bc": {
"allowed": true,
"error": {
"message": ""
}
}
}
}{
"code": "validation_error",
"message": "Generic validation error"
}{
"code": "unauthenticated",
"message": "unauthenticated"
}{
"code": "forbidden",
"message": "the principal is not authorized to perform the action"
}{
"code": "undefined_endpoint",
"message": "Endpoint not enabled"
}{
"code": "10",
"message": "transaction conflict"
}{
"code": "throttled_timeout_error",
"message": "timeout due to throttling on complex request"
}{
"code": "internal_error",
"message": "Internal Server Error"
}