https://github.com/openfga/java-sdk
OpenFGA SDK for Java - https://central.sonatype.com/artifact/dev.openfga/openfga-sdk
https://github.com/openfga/java-sdk
access-control authorization fga fine-grained-authorization hacktoberfest java openfga openfga-client security zanzibar
Last synced: 10 days ago
JSON representation
OpenFGA SDK for Java - https://central.sonatype.com/artifact/dev.openfga/openfga-sdk
- Host: GitHub
- URL: https://github.com/openfga/java-sdk
- Owner: openfga
- License: apache-2.0
- Created: 2023-07-24T15:05:21.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2025-06-20T16:57:55.000Z (8 months ago)
- Last Synced: 2025-06-20T17:45:36.416Z (8 months ago)
- Topics: access-control, authorization, fga, fine-grained-authorization, hacktoberfest, java, openfga, openfga-client, security, zanzibar
- Language: Java
- Homepage: https://openfga.dev
- Size: 1.22 MB
- Stars: 39
- Watchers: 16
- Forks: 14
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
- awesome - openfga/java-sdk - OpenFGA SDK for Java - https://central.sonatype.com/artifact/dev.openfga/openfga-sdk (<a name="Java"></a>Java)
README
# Java SDK for OpenFGA
[](https://central.sonatype.com/artifact/dev.openfga/openfga-sdk)
[](https://javadoc.io/doc/dev.openfga/openfga-sdk)
[](https://socket.dev/maven/package/dev.openfga:openfga-sdk)
[](https://deepwiki.com/openfga/java-sdk)
[](https://github.com/openfga/java-sdk/releases)
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fopenfga%2Fjava-sdk?ref=badge_shield)
[](https://securityscorecards.dev/viewer/?uri=github.com/openfga/java-sdk)
[](https://openfga.dev/community)
[](https://x.com/openfga)
This is an autogenerated Java SDK for OpenFGA. It provides a wrapper around the [OpenFGA API definition](https://openfga.dev/api).
## Table of Contents
- [About OpenFGA](#about)
- [Resources](#resources)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Initializing the API Client](#initializing-the-api-client)
- [Custom Headers](#custom-headers)
- [Get your Store ID](#get-your-store-id)
- [Calling the API](#calling-the-api)
- [Stores](#stores)
- [List All Stores](#list-stores)
- [Create a Store](#create-store)
- [Get a Store](#get-store)
- [Delete a Store](#delete-store)
- [Authorization Models](#authorization-models)
- [Read Authorization Models](#read-authorization-models)
- [Write Authorization Model](#write-authorization-model)
- [Read a Single Authorization Model](#read-a-single-authorization-model)
- [Read the Latest Authorization Model](#read-the-latest-authorization-model)
- [Relationship Tuples](#relationship-tuples)
- [Read Relationship Tuple Changes (Watch)](#read-relationship-tuple-changes-watch)
- [Read Relationship Tuples](#read-relationship-tuples)
- [Write (Create and Delete) Relationship Tuples](#write-create-and-delete-relationship-tuples)
- [Relationship Queries](#relationship-queries)
- [Check](#check)
- [Batch Check](#batch-check)
- [Expand](#expand)
- [List Objects](#list-objects)
- [List Relations](#list-relations)
- [List Users](#list-users)
- [Assertions](#assertions)
- [Read Assertions](#read-assertions)
- [Write Assertions](#write-assertions)
- [Retries](#retries)
- [API Endpoints](#api-endpoints)
- [Models](#models)
- [OpenTelemetry](#opentelemetry)
- [Contributing](#contributing)
- [Issues](#issues)
- [Pull Requests](#pull-requests)
- [License](#license)
## About
[OpenFGA](https://openfga.dev) is an open source Fine-Grained Authorization solution inspired by [Google's Zanzibar paper](https://research.google/pubs/pub48190/). It was created by the FGA team at [Auth0](https://auth0.com) based on [Auth0 Fine-Grained Authorization (FGA)](https://fga.dev), available under [a permissive license (Apache-2)](https://github.com/openfga/rfcs/blob/main/LICENSE) and welcomes community contributions.
OpenFGA is designed to make it easy for application builders to model their permission layer, and to add and integrate fine-grained authorization into their applications. OpenFGA’s design is optimized for reliability and low latency at a high scale.
## Resources
- [OpenFGA Documentation](https://openfga.dev/docs)
- [OpenFGA API Documentation](https://openfga.dev/api/service)
- [X](https://x.com/openfga)
- [OpenFGA Community](https://openfga.dev/community)
- [Zanzibar Academy](https://zanzibar.academy)
- [Google's Zanzibar Paper (2019)](https://research.google/pubs/pub48190/)
## Installation
The OpenFGA Java SDK is available on [Maven Central](https://central.sonatype.com/).
The OpenFGA Java SDK currently supports **Java 11** as the minimum JDK version.
It can be used with the following:
* Gradle (Groovy)
```groovy
implementation 'dev.openfga:openfga-sdk:0.9.5'
```
* Gradle (Kotlin)
```kotlin
implementation("dev.openfga:openfga-sdk:0.9.5")
```
* Apache Maven
```xml
dev.openfga
openfga-sdk
0.9.5
```
* Ivy
```xml
```
* SBT
```scala
libraryDependencies += "dev.openfga" % "openfga-sdk" % "0.9.5"
```
* Leiningen
```edn
[dev.openfga/openfga-sdk "0.9.5"]
```
## Getting Started
### Initializing the API Client
[Learn how to initialize your SDK](https://openfga.dev/docs/getting-started/setup-sdk-client)
We strongly recommend you initialize the `OpenFgaClient` only once and then re-use it throughout your app, otherwise you will incur the cost of having to re-initialize multiple times or at every request, the cost of reduced connection pooling and re-use, and would be particularly costly in the client credentials flow, as that flow will be preformed on every request.
> The `Client` will by default retry API requests up to 3 times. Rate limiting (429) errors are always retried. Server errors (5xx) are retried for all operations, with delay calculation using `Retry-After` headers when provided or exponential backoff as fallback.
#### No Credentials
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import java.net.http.HttpClient;
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 "http://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_MODEL_ID")); // Optional, can be overridden per request
var fgaClient = new OpenFgaClient(config);
var response = fgaClient.readAuthorizationModels().get();
}
}
```
#### API Token
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ApiToken;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.Credentials;
import java.net.http.HttpClient;
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 "http://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.credentials(new Credentials(
new ApiToken(System.getenv("FGA_API_TOKEN")) // will be passed as the "Authorization: Bearer ${ApiToken}" request header
));
var fgaClient = new OpenFgaClient(config);
var response = fgaClient.readAuthorizationModels().get();
}
}
```
#### Client Credentials
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.ClientCredentials;
import dev.openfga.sdk.api.configuration.Credentials;
import java.net.http.HttpClient;
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 "http://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.credentials(new Credentials(
new ClientCredentials()
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER"))
.apiAudience(System.getenv("FGA_API_AUDIENCE"))
.clientId(System.getenv("FGA_CLIENT_ID"))
.clientSecret(System.getenv("FGA_CLIENT_SECRET"))
));
var fgaClient = new OpenFgaClient(config);
var response = fgaClient.readAuthorizationModels().get();
}
}
```
#### Oauth2 Credentials
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import dev.openfga.sdk.api.configuration.ClientCredentials;
import dev.openfga.sdk.api.configuration.Credentials;
import java.net.http.HttpClient;
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 "http://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.credentials(new Credentials(
new ClientCredentials()
.apiTokenIssuer(System.getenv("FGA_API_TOKEN_ISSUER"))
.scopes(System.getenv("FGA_API_SCOPES")) // optional space separated scopes
.clientId(System.getenv("FGA_CLIENT_ID"))
.clientSecret(System.getenv("FGA_CLIENT_SECRET"))
));
var fgaClient = new OpenFgaClient(config);
var response = fgaClient.readAuthorizationModels().get();
}
}
```
### Custom Headers
#### Default Headers
You can set default headers to be sent with every request by using the `defaultHeaders` property of the `ClientConfiguration` class.
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import java.net.http.HttpClient;
import java.util.Map;
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"))
.defaultHeaders(Map.of(
"X-Custom-Header", "default-value",
"X-Request-Source", "my-app"
));
var fgaClient = new OpenFgaClient(config);
}
}
```
#### Per-request Headers
You can set custom headers to be sent with a specific request by using the `additionalHeaders` property of the options classes (e.g. `ClientReadOptions`, `ClientWriteOptions`, etc.).
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import java.net.http.HttpClient;
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"))
.defaultHeaders(Map.of(
"X-Custom-Header", "default-value",
"X-Request-Source", "my-app"
));
var fgaClient = new OpenFgaClient(config);
var options = new ClientReadOptions()
.additionalHeaders(Map.of(
"X-Request-Id", "123e4567-e89b-12d3-a456-426614174000",
"X-Custom-Header", "overridden-value" // this will override the default value for this request only
)
);
var response = fgaClient.read(request, options).get();
}
}
```
### Get your Store ID
You need your store id to call the OpenFGA API (unless it is to call the [CreateStore](#create-store) or [ListStores](#list-stores) methods).
If your server is configured with [authentication enabled](https://openfga.dev/docs/getting-started/setup-openfga#configuring-authentication), you also need to have your credentials ready.
### Calling the API
#### Stores
##### List Stores
Get a paginated list of stores.
[API Documentation](https://openfga.dev/api/service#/Stores/ListStores)
> Passing `ClientListStoresOptions` is optional. All fields of `ClientListStoresOptions` are optional.
```java
var options = new ClientListStoresOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.pageSize(10)
.continuationToken("...");
var stores = fgaClient.listStores(options);
// stores = [{ "id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z" }]
```
##### Create Store
Initialize a store.
[API Documentation](https://openfga.dev/api/service#/Stores/CreateStore)
> Passing `ClientCreateStoreOptions` is optional. All fields of `ClientCreateStoreOptions` are optional.
```java
var request = new CreateStoreRequest().name("FGA Demo");
var options = new ClientCreateStoreOptions().additionalHeaders(Map.of("Some-Http-Header", "Some value"));
var store = fgaClient.createStore(request, options).get();
// store.getId() = "01FQH7V8BEG3GPQW93KTRFR8JB"
// store the store.getId() in database
// update the storeId of the client instance
fgaClient.setStoreId(store.getId());
// continue calling the API normally
```
##### Get Store
Get information about the current store.
[API Documentation](https://openfga.dev/api/service#/Stores/GetStore)
> Requires a client initialized with a storeId
> Passing `ClientGetStoreOptions` is optional. All fields of `ClientGetStoreOptions` are optional.
```java
var options = new ClientGetStoreOptions().additionalHeaders(Map.of("Some-Http-Header", "Some value"));
var store = fgaClient.getStore(options).get();
// store = { "id": "01FQH7V8BEG3GPQW93KTRFR8JB", "name": "FGA Demo Store", "created_at": "2022-01-01T00:00:00.000Z", "updated_at": "2022-01-01T00:00:00.000Z" }
```
##### Delete Store
Delete a store.
[API Documentation](https://openfga.dev/api/service#/Stores/DeleteStore)
> Requires a client initialized with a storeId
> Passing `ClientDeleteStoreOptions` is optional. All fields of `ClientDeleteStoreOptions` are optional.
```java
var options = new ClientDeleteStoreOptions().additionalHeaders(Map.of("Some-Http-Header", "Some value"));
var store = fgaClient.deleteStore(options).get();
```
#### Authorization Models
##### Read Authorization Models
Read all authorization models in the store.
[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModels)
> Passing `ClientReadAuthorizationModelsOptions` is optional. All fields of `ClientReadAuthorizationModelsOptions` are optional.
```java
var options = new ClientReadAuthorizationModelsOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.pageSize(10)
.continuationToken("...");
var response = fgaClient.readAuthorizationModels(options).get();
// response.getAuthorizationModels() = [
// { id: "01GXSA8YR785C4FYS3C0RTG7B1", schemaVersion: "1.1", typeDefinitions: [...] },
// { id: "01GXSBM5PVYHCJNRNKXMB4QZTW", schemaVersion: "1.1", typeDefinitions: [...] }];
```
##### Write Authorization Model
Create a new authorization model.
[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/WriteAuthorizationModel)
> Note: To learn how to build your authorization model, check the Docs at https://openfga.dev/docs.
> Learn more about [the OpenFGA configuration language](https://openfga.dev/docs/configuration-language).
> You can use the OpenFGA [CLI](https://github.com/openfga/cli) or [Syntax Transformer](https://github.com/openfga/syntax-transformer) to convert between the OpenFGA DSL and the JSON authorization model.
> Passing `ClientWriteAuthorizationModelOptions` is optional. All fields of `ClientWriteAuthorizationModelOptions` are optional.
```java
var request = new WriteAuthorizationModelRequest()
.schemaVersion("1.1")
.typeDefinitions(List.of(
new TypeDefinition().type("user").relations(Map.of()),
new TypeDefinition()
.type("document")
.relations(Map.of(
"writer", new Userset(),
"viewer", new Userset().union(new Usersets()
.child(List.of(
new Userset(),
new Userset().computedUserset(new ObjectRelation().relation("writer"))
))
)
))
.metadata(new Metadata()
.relations(Map.of(
"writer", new RelationMetadata().directlyRelatedUserTypes(
List.of(new RelationReference().type("user"))
),
"viewer", new RelationMetadata().directlyRelatedUserTypes(
List.of(new RelationReference().type("user"))
)
))
)
));
var options = new ClientWriteAuthorizationModelOptions().additionalHeaders(Map.of("Some-Http-Header", "Some value"));
var response = fgaClient.writeAuthorizationModel(request, options).get();
// response.getAuthorizationModelId() = "01GXSA8YR785C4FYS3C0RTG7B1"
```
#### Read a Single Authorization Model
Read a particular authorization model.
[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModel)
> Passing `ClientReadAuthorizationModelOptions` is optional. All fields of `ClientReadAuthorizationModelOptions` are optional.
```java
var options = new ClientReadAuthorizationModelOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.readAuthorizationModel(options).get();
// response.getAuthorizationModel().getId() = "01GXSA8YR785C4FYS3C0RTG7B1"
// response.getAuthorizationModel().getSchemaVersion() = "1.1"
// response.getAuthorizationModel().getTypeDefinitions() = [{ "type": "document", "relations": { ... } }, { "type": "user", "relations": { ... }}]
```
##### Read the Latest Authorization Model
Reads the latest authorization model (note: this ignores the model id in configuration).
[API Documentation](https://openfga.dev/api/service#/Authorization%20Models/ReadAuthorizationModel)
> Passing `ClientReadLatestAuthorizationModelOptions` is optional. All fields of `ClientReadLatestAuthorizationModelOptions` are optional.
```java
var options = new ClientReadLatestAuthorizationModelOptions().additionalHeaders(Map.of("Some-Http-Header", "Some value"));
var response = fgaClient.readLatestAuthorizationModel(options).get();
// response.getAuthorizationModel().getId() = "01GXSA8YR785C4FYS3C0RTG7B1"
// response.getAuthorizationModel().SchemaVersion() = "1.1"
// response.getAuthorizationModel().TypeDefinitions() = [{ "type": "document", "relations": { ... } }, { "type": "user", "relations": { ... }}]
```
#### Relationship Tuples
##### Read Relationship Tuple Changes (Watch)
Reads the list of historical relationship tuple writes and deletes.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/ReadChanges)
> Passing `ClientReadChangesOptions` is optional. All fields of `ClientReadChangesOptions` are optional.
```java
var startTime = OffsetDateTime.parse("2022-01-01T00:00:00+00:00");
var request = new ClientReadChangesRequest().type("document").startTime(startTime);
var options = new ClientReadChangesOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.pageSize(10)
.continuationToken("...");
var response = fgaClient.readChanges(request, options).get();
// response.getContinuationToken() = ...
// response.getChanges() = [
// { tupleKey: { user, relation, object }, operation: TupleOperation.WRITE, timestamp: ... },
// { tupleKey: { user, relation, object }, operation: TupleOperation.DELETE, timestamp: ... }
// ]
```
##### Read Relationship Tuples
Reads the relationship tuples stored in the database. It does not evaluate nor exclude invalid tuples according to the authorization model.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/Read)
> Passing `ClientReadOptions` is optional. All fields of `ClientReadOptions` are optional.
```java
// Find if a relationship tuple stating that a certain user is a viewer of a certain document
var request = new ClientReadRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a");
// Find all relationship tuples where a certain user has a relationship as any relation to a certain document
var request = new ClientReadRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a");
// Find all relationship tuples where a certain user is a viewer of any document
var request = new ClientReadRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:");
// Find all relationship tuples where any user has a relationship as any relation with a particular document
var request = new ClientReadRequest()
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a");
// Read all stored relationship tuples
var request = new ClientReadRequest();
var options = new ClientReadOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.pageSize(10)
.continuationToken("...");
var response = fgaClient.read(request, options).get();
// In all the above situations, the response will be of the form:
// response = { tuples: [{ key: { user, relation, object }, timestamp }, ...]}
```
##### Write (Create and Delete) Relationship Tuples
Create and/or delete relationship tuples to update the system state.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Tuples/Write)
> Passing `ClientWriteOptions` is optional. All fields of `ClientWriteOptions` are optional.
###### Transaction mode (default)
By default, write runs in a transaction mode where any invalid operation (deleting a non-existing tuple, creating an existing tuple, one of the tuples was invalid) or a server error will fail the entire operation.
```java
var request = new ClientWriteRequest()
.writes(List.of(
new TupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"),
new TupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5")
))
.deletes(List.of(
new TupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
));
var options = new ClientWriteOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1")
.disableTransactions(false);
var response = fgaClient.write(request, options).get();
```
Convenience `WriteTuples` and `DeleteTuples` methods are also available.
###### Non-transaction mode
The SDK will split the writes into separate requests and send them sequentially to avoid violating rate limits.
> Passing `ClientWriteOptions` with `.disableTransactions(true)` is required to use non-transaction mode.
> All other fields of `ClientWriteOptions` are optional.
```java
var request = new ClientWriteRequest()
.writes(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"),
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5")
))
.deletes(List.of(
new ClientTupleKeyWithoutCondition()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
));
var options = new ClientWriteOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1")
.disableTransactions(true)
.transactionChunkSize(5); // Maximum number of requests to be sent in a transaction in a particular chunk
var response = fgaClient.write(request, options).get();
```
###### Conflict options for write operations
Write conflict handling can be controlled using the `onDuplicate` option for writes and the `onMissing` option for deletes.
> Note: this requires OpenFGA [v1.10.0](https://github.com/openfga/openfga/releases/tag/v1.10.0) or later.
- `onDuplicate`: Controls behavior when attempting to create a tuple that already exists
- `WriteRequestWrites.OnDuplicateEnum.ERROR` (default): Return an error
- `WriteRequestWrites.OnDuplicateEnum.IGNORE`: Skip the duplicate tuple and continue
- `onMissing`: Controls behavior when attempting to delete a tuple that doesn't exist
- `WriteRequestDeletes.OnMissingEnum.ERROR` (default): Return an error
- `WriteRequestDeletes.OnMissingEnum.IGNORE`: Skip the missing tuple and continue
**Using conflict options with the `write()` method:**
```java
var request = new ClientWriteRequest()
.writes(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
))
.deletes(List.of(
new ClientTupleKeyWithoutCondition()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
));
var options = new ClientWriteOptions()
.onDuplicate(WriteRequestWrites.OnDuplicateEnum.IGNORE)
.onMissing(WriteRequestDeletes.OnMissingEnum.IGNORE);
var response = fgaClient.write(request, options).get();
```
**Using conflict options with the `writeTuples()` convenience method:**
```java
var tuples = List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
);
var options = new ClientWriteTuplesOptions()
.onDuplicate(WriteRequestWrites.OnDuplicateEnum.IGNORE);
var response = fgaClient.writeTuples(tuples, options).get();
```
**Using conflict options with the `deleteTuples()` convenience method:**
```java
var tuples = List.of(
new ClientTupleKeyWithoutCondition()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
);
var options = new ClientDeleteTuplesOptions()
.onMissing(WriteRequestDeletes.OnMissingEnum.IGNORE);
var response = fgaClient.deleteTuples(tuples, options).get();
```
#### Relationship Queries
##### Check
Check if a user has a particular relation with an object.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/Check)
> Passing `ClientCheckOptions` is optional. All fields of `ClientCheckOptions` are optional.
```java
var request = new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a");
var options = new ClientCheckOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.check(request, options).get();
// response.getAllowed() = true
```
##### Batch Check
Similar to [check](#check), but instead of checking a single user-object relationship, accepts a list of relationships to check. Requires OpenFGA version 1.8.0 or greater.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/BatchCheck)
> **Note**: The order of `batchCheck` results is not guaranteed to match the order of the checks provided. Use `correlationId` to pair responses with requests.
> Passing `ClientBatchCheckOptions` is optional. All fields of `ClientBatchCheckOptions` are optional.
```java
var reequst = new ClientBatchCheckRequest().checks(
List.of(
new ClientBatchCheckItem()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.correlationId("cor-1") // optional, one will be generated for you if not provided
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
)),
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("admin")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"),
.correlationId("cor-2") // optional, one will be generated for you if not provided
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
)),
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("creator")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.correlationId("cor-3), // optional, one will be generated for you if not provided
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("deleter")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.correlationId("cor-4") // optional, one will be generated for you if not provided
)
);
var options = new ClientBatchCheckOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1")
.maxParallelRequests(5); // Max number of requests to issue in parallel, defaults to 10
.maxBatchSize(20); // Max number of batches to split the list of checks into, defaults to 50
var response = fgaClient.batchCheck(request, options).get();
/*
response.getResult() = [{
allowed: false,
correlationId: "cor-1",
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "viewer",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
correlationId: "cor-1",
contextualTuples: [{
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "editor",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
}]
},
},
{
allowed: false,
correlationId: "cor-2",
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "admin",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
correlationId: "cor-2",
contextualTuples: [{
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "editor",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
}]
}
},
{
allowed: false,
correlationId: "cor-3",
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "creator",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
correlationId: "cor-3",
},
error:
},
{
allowed: true,
correlationId: "cor-4",
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "deleter",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
correlationId: "cor-4",
}
},
]
*/
```
If you are using an OpenFGA version less than 1.8.0, you can use `clientBatchCheck`,
which calls `check` in parallel. It will return `allowed: false` if it encounters an error, and will return the error in the body.
If 429s are encountered, the underlying check will retry up to 3 times. For 5xx errors, all requests will retry with delay calculation using `Retry-After` headers when provided or exponential backoff as fallback.
```
var request = List.of(
new ClientBatchCheckItem()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
)),
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("admin")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"),
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
)),
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("creator")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"),
new ClientCheckRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("deleter")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
);
var options = new ClientBatchCheckClientOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1")
.maxParallelRequests(5); // Max number of requests to issue in parallel, defaults to 10
var response = fgaClient.batchCheck(request, options).get();
/*
response.getResponses() = [{
allowed: false,
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "viewer",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
contextualTuples: [{
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "editor",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
}]
}
}, {
allowed: false,
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "admin",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
contextualTuples: [{
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "editor",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"
}]
}
}, {
allowed: false,
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "creator",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
},
error:
}, {
allowed: true,
request: {
user: "user:81684243-9356-4421-8fbf-a4f8d36aa31b",
relation: "deleter",
_object: "document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a",
}},
]
*/
```
##### Expand
Expands the relationships in userset tree format.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/Expand)
> Passing `ClientExpandOptions` is optional. All fields of `ClientExpandOptions` are optional.
```java
var request = new ClientExpandRequest()
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a");
var options = new ClientExpandOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.expand(request, options).get();
// response.getTree().getRoot() = {"name":"document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a#viewer","leaf":{"users":{"users":["user:81684243-9356-4421-8fbf-a4f8d36aa31b","user:f52a4f7a-054d-47ff-bb6e-3ac81269988f"]}}}
```
##### List Objects
List the objects of a particular type a user has access to.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/ListObjects)
> Passing `ClientListObjectsOptions` is optional. All fields of `ClientListObjectsOptions` are optional.
```java
var request = new ClientListObjectsRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
.type("document")
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("writer")
._object("document:0192ab2d-d36e-7cb3-a4a8-5d1d67a300c5")
));
var options = new ClientListObjectsOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.listObjects(request, options).get();
// response.getObjects() = ["document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a"]
```
##### List Relations
List the relations a user has on an object.
> Passing `ClientListRelationsOptions` is optional. All fields of `ClientListRelationsOptions` are optional.
```java
var request = new ClientListRelationsRequest()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.relations(List.of("can_view", "can_edit", "can_delete", "can_rename"))
.contextualTuples(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
)
);
var options = new ClientListRelationsOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// When unspecified, defaults to 10
.maxParallelRequests()
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId(DEFAULT_AUTH_MODEL_ID);
var response = fgaClient.listRelations(request, options).get();
// response.getRelations() = ["can_view", "can_edit"]
```
##### List Users
List the users who have a certain relation to a particular type.
[API Documentation](https://openfga.dev/api/service#/Relationship%20Queries/ListUsers)
```java
// Only a single filter is allowed for the time being
var userFilters = new ArrayList() {
{
add(new UserTypeFilter().type("user"));
// user filters can also be of the form
// add(new UserTypeFilter().type("team").relation("member"));
}
};
var request = new ClientListUsersRequest()
._object(new FgaObject().type("document").id("roadmap"))
.relation("can_read")
.userFilters(userFilters)
.context(Map.of("view_count", 100))
.contextualTupleKeys(List.of(
new ClientTupleKey()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("editor")
._object("folder:product"),
new ClientTupleKey()
.user("folder:product")
.relation("parent")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
));
var options = new ClientListUsersOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.listUsers(request, options).get();
// response.getUsers() = [{object: {type: "user", id: "81684243-9356-4421-8fbf-a4f8d36aa31b"}}, {userset: { type: "user" }}, ...]
```
#### Assertions
##### Read Assertions
Read assertions for a particular authorization model.
[API Documentation](https://openfga.dev/api/service#/Assertions/Read%20Assertions)
> Passing `ClientReadAssertionsOptions` is optional. All fields of `ClientReadAssertionsOptions` are optional.
```java
var options = new ClientReadAssertionsOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
// You can rely on the model id set in the configuration or override it for this specific request
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var response = fgaClient.readAssertions(options).get();
```
##### Write Assertions
Update the assertions for a particular authorization model.
[API Documentation](https://openfga.dev/api/service#/Assertions/Write%20Assertions)
> Passing `ClientWriteAssertionsOptions` is optional. All fields of `ClientWriteAssertionsOptions` are optional.
```java
var options = new ClientWriteAssertionsOptions()
.additionalHeaders(Map.of("Some-Http-Header", "Some value"))
.authorizationModelId("01GXSA8YR785C4FYS3C0RTG7B1");
var assertions = List.of(
new ClientAssertion()
.user("user:81684243-9356-4421-8fbf-a4f8d36aa31b")
.relation("viewer")
._object("document:0192ab2a-d83f-756d-9397-c5ed9f3cb69a")
.expectation(true)
);
fgaClient.writeAssertions(assertions, options).get();
```
### Retries
The SDK implements RFC 9110 compliant retry behavior with support for the `Retry-After` header. By default, the SDK will automatically retry failed requests up to **3 times** with delay calculation (maximum allowable: 15 retries).
#### Retry Behavior
**Rate Limiting (429 errors):** Always retried regardless of HTTP method.
**Server Errors (5xx):** All requests are retried on 5xx errors (except 501 Not Implemented) regardless of HTTP method:
- **All operations** (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS): Always retried on 5xx errors with delay calculation
#### Delay Calculation
1. **Retry-After header present**: Uses the server-specified delay (supports both integer seconds and HTTP-date formats)
2. **No Retry-After header**: Uses exponential backoff with jitter (base delay: 2^retryCount * 100ms, capped at 120 seconds)
3. **Minimum delay**: Respects the configured `minimumRetryDelay` as a floor value
#### Configuration
Customize retry behavior using the `ClientConfiguration` builder. The SDK enforces a maximum of 15 retries to prevent accidental server overload:
**⚠️ Breaking Changes:**
- Configuration validation now prevents setting `maxRetries` above 15
- `FgaError` now exposes the `Retry-After` header value via `getRetryAfterHeader()`
```java
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.openfga.sdk.api.client.OpenFgaClient;
import dev.openfga.sdk.api.configuration.ClientConfiguration;
import java.net.http.HttpClient;
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 "http://localhost:8080"
.storeId(System.getenv("FGA_STORE_ID")) // Not required when calling createStore() or listStores()
.authorizationModelId(System.getenv("FGA_MODEL_ID")) // Optional, can be overridden per request
.maxRetries(3) // retry up to 3 times on API requests (default: 3, maximum: 15)
.minimumRetryDelay(Duration.ofMillis(100)); // minimum wait time between retries in milliseconds (default: 100ms)
var fgaClient = new OpenFgaClient(config);
var response = fgaClient.readAuthorizationModels().get();
}
}
```
#### Error Handling with Retry Information
When handling errors, you can access the `Retry-After` header value for debugging or custom retry logic:
```java
try {
var response = fgaClient.check(request).get();
} catch (ExecutionException e) {
if (e.getCause() instanceof FgaError) {
FgaError error = (FgaError) e.getCause();
// Access Retry-After header if present
String retryAfter = error.getRetryAfterHeader();
if (retryAfter != null) {
System.out.println("Server requested retry after: " + retryAfter + " seconds");
}
System.out.println("Error: " + error.getMessage());
}
}
```
### API Endpoints
| Method | HTTP request | Description |
| ------------- | ------------- | ------------- |
| [**batchCheck**](docs/OpenFgaApi.md#batchcheck) | **POST** /stores/{store_id}/batch-check | Send a list of `check` operations in a single request |
| [**check**](docs/OpenFgaApi.md#check) | **POST** /stores/{store_id}/check | Check whether a user is authorized to access an object |
| [**createStore**](docs/OpenFgaApi.md#createstore) | **POST** /stores | Create a store |
| [**deleteStore**](docs/OpenFgaApi.md#deletestore) | **DELETE** /stores/{store_id} | Delete a store |
| [**expand**](docs/OpenFgaApi.md#expand) | **POST** /stores/{store_id}/expand | Expand all relationships in userset tree format, and following userset rewrite rules. Useful to reason about and debug a certain relationship |
| [**getStore**](docs/OpenFgaApi.md#getstore) | **GET** /stores/{store_id} | Get a store |
| [**listObjects**](docs/OpenFgaApi.md#listobjects) | **POST** /stores/{store_id}/list-objects | List all objects of the given type that the user has a relation with |
| [**listStores**](docs/OpenFgaApi.md#liststores) | **GET** /stores | List all stores |
| [**listUsers**](docs/OpenFgaApi.md#listusers) | **POST** /stores/{store_id}/list-users | List the users matching the provided filter who have a certain relation to a particular type. |
| [**read**](docs/OpenFgaApi.md#read) | **POST** /stores/{store_id}/read | Get tuples from the store that matches a query, without following userset rewrite rules |
| [**readAssertions**](docs/OpenFgaApi.md#readassertions) | **GET** /stores/{store_id}/assertions/{authorization_model_id} | Read assertions for an authorization model ID |
| [**readAuthorizationModel**](docs/OpenFgaApi.md#readauthorizationmodel) | **GET** /stores/{store_id}/authorization-models/{id} | Return a particular version of an authorization model |
| [**readAuthorizationModels**](docs/OpenFgaApi.md#readauthorizationmodels) | **GET** /stores/{store_id}/authorization-models | Return all the authorization models for a particular store |
| [**readChanges**](docs/OpenFgaApi.md#readchanges) | **GET** /stores/{store_id}/changes | Return a list of all the tuple changes |
| [**streamedListObjects**](docs/OpenFgaApi.md#streamedlistobjects) | **POST** /stores/{store_id}/streamed-list-objects | Stream all objects of the given type that the user has a relation with |
| [**write**](docs/OpenFgaApi.md#write) | **POST** /stores/{store_id}/write | Add or delete tuples from the store |
| [**writeAssertions**](docs/OpenFgaApi.md#writeassertions) | **PUT** /stores/{store_id}/assertions/{authorization_model_id} | Upsert assertions for an authorization model ID |
| [**writeAuthorizationModel**](docs/OpenFgaApi.md#writeauthorizationmodel) | **POST** /stores/{store_id}/authorization-models | Create a new authorization model |
### Models
- [AbortedMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/AbortedMessageResponse.md)
- [Any](https://github.com/openfga/java-sdk/blob/main/docs/Any.md)
- [Assertion](https://github.com/openfga/java-sdk/blob/main/docs/Assertion.md)
- [AssertionTupleKey](https://github.com/openfga/java-sdk/blob/main/docs/AssertionTupleKey.md)
- [AuthErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/AuthErrorCode.md)
- [AuthorizationModel](https://github.com/openfga/java-sdk/blob/main/docs/AuthorizationModel.md)
- [BatchCheckItem](https://github.com/openfga/java-sdk/blob/main/docs/BatchCheckItem.md)
- [BatchCheckRequest](https://github.com/openfga/java-sdk/blob/main/docs/BatchCheckRequest.md)
- [BatchCheckResponse](https://github.com/openfga/java-sdk/blob/main/docs/BatchCheckResponse.md)
- [BatchCheckSingleResult](https://github.com/openfga/java-sdk/blob/main/docs/BatchCheckSingleResult.md)
- [CheckError](https://github.com/openfga/java-sdk/blob/main/docs/CheckError.md)
- [CheckRequest](https://github.com/openfga/java-sdk/blob/main/docs/CheckRequest.md)
- [CheckRequestTupleKey](https://github.com/openfga/java-sdk/blob/main/docs/CheckRequestTupleKey.md)
- [CheckResponse](https://github.com/openfga/java-sdk/blob/main/docs/CheckResponse.md)
- [Computed](https://github.com/openfga/java-sdk/blob/main/docs/Computed.md)
- [Condition](https://github.com/openfga/java-sdk/blob/main/docs/Condition.md)
- [ConditionMetadata](https://github.com/openfga/java-sdk/blob/main/docs/ConditionMetadata.md)
- [ConditionParamTypeRef](https://github.com/openfga/java-sdk/blob/main/docs/ConditionParamTypeRef.md)
- [ConsistencyPreference](https://github.com/openfga/java-sdk/blob/main/docs/ConsistencyPreference.md)
- [ContextualTupleKeys](https://github.com/openfga/java-sdk/blob/main/docs/ContextualTupleKeys.md)
- [CreateStoreRequest](https://github.com/openfga/java-sdk/blob/main/docs/CreateStoreRequest.md)
- [CreateStoreResponse](https://github.com/openfga/java-sdk/blob/main/docs/CreateStoreResponse.md)
- [Difference](https://github.com/openfga/java-sdk/blob/main/docs/Difference.md)
- [ErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/ErrorCode.md)
- [ExpandRequest](https://github.com/openfga/java-sdk/blob/main/docs/ExpandRequest.md)
- [ExpandRequestTupleKey](https://github.com/openfga/java-sdk/blob/main/docs/ExpandRequestTupleKey.md)
- [ExpandResponse](https://github.com/openfga/java-sdk/blob/main/docs/ExpandResponse.md)
- [FgaObject](https://github.com/openfga/java-sdk/blob/main/docs/FgaObject.md)
- [ForbiddenResponse](https://github.com/openfga/java-sdk/blob/main/docs/ForbiddenResponse.md)
- [GetStoreResponse](https://github.com/openfga/java-sdk/blob/main/docs/GetStoreResponse.md)
- [InternalErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/InternalErrorCode.md)
- [InternalErrorMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/InternalErrorMessageResponse.md)
- [Leaf](https://github.com/openfga/java-sdk/blob/main/docs/Leaf.md)
- [ListObjectsRequest](https://github.com/openfga/java-sdk/blob/main/docs/ListObjectsRequest.md)
- [ListObjectsResponse](https://github.com/openfga/java-sdk/blob/main/docs/ListObjectsResponse.md)
- [ListStoresResponse](https://github.com/openfga/java-sdk/blob/main/docs/ListStoresResponse.md)
- [ListUsersRequest](https://github.com/openfga/java-sdk/blob/main/docs/ListUsersRequest.md)
- [ListUsersResponse](https://github.com/openfga/java-sdk/blob/main/docs/ListUsersResponse.md)
- [Metadata](https://github.com/openfga/java-sdk/blob/main/docs/Metadata.md)
- [Node](https://github.com/openfga/java-sdk/blob/main/docs/Node.md)
- [Nodes](https://github.com/openfga/java-sdk/blob/main/docs/Nodes.md)
- [NotFoundErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/NotFoundErrorCode.md)
- [NullValue](https://github.com/openfga/java-sdk/blob/main/docs/NullValue.md)
- [ObjectRelation](https://github.com/openfga/java-sdk/blob/main/docs/ObjectRelation.md)
- [PathUnknownErrorMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/PathUnknownErrorMessageResponse.md)
- [ReadAssertionsResponse](https://github.com/openfga/java-sdk/blob/main/docs/ReadAssertionsResponse.md)
- [ReadAuthorizationModelResponse](https://github.com/openfga/java-sdk/blob/main/docs/ReadAuthorizationModelResponse.md)
- [ReadAuthorizationModelsResponse](https://github.com/openfga/java-sdk/blob/main/docs/ReadAuthorizationModelsResponse.md)
- [ReadChangesResponse](https://github.com/openfga/java-sdk/blob/main/docs/ReadChangesResponse.md)
- [ReadRequest](https://github.com/openfga/java-sdk/blob/main/docs/ReadRequest.md)
- [ReadRequestTupleKey](https://github.com/openfga/java-sdk/blob/main/docs/ReadRequestTupleKey.md)
- [ReadResponse](https://github.com/openfga/java-sdk/blob/main/docs/ReadResponse.md)
- [RelationMetadata](https://github.com/openfga/java-sdk/blob/main/docs/RelationMetadata.md)
- [RelationReference](https://github.com/openfga/java-sdk/blob/main/docs/RelationReference.md)
- [RelationshipCondition](https://github.com/openfga/java-sdk/blob/main/docs/RelationshipCondition.md)
- [SourceInfo](https://github.com/openfga/java-sdk/blob/main/docs/SourceInfo.md)
- [Status](https://github.com/openfga/java-sdk/blob/main/docs/Status.md)
- [Store](https://github.com/openfga/java-sdk/blob/main/docs/Store.md)
- [StreamResultOfStreamedListObjectsResponse](https://github.com/openfga/java-sdk/blob/main/docs/StreamResultOfStreamedListObjectsResponse.md)
- [StreamedListObjectsResponse](https://github.com/openfga/java-sdk/blob/main/docs/StreamedListObjectsResponse.md)
- [Tuple](https://github.com/openfga/java-sdk/blob/main/docs/Tuple.md)
- [TupleChange](https://github.com/openfga/java-sdk/blob/main/docs/TupleChange.md)
- [TupleKey](https://github.com/openfga/java-sdk/blob/main/docs/TupleKey.md)
- [TupleKeyWithoutCondition](https://github.com/openfga/java-sdk/blob/main/docs/TupleKeyWithoutCondition.md)
- [TupleOperation](https://github.com/openfga/java-sdk/blob/main/docs/TupleOperation.md)
- [TupleToUserset](https://github.com/openfga/java-sdk/blob/main/docs/TupleToUserset.md)
- [TypeDefinition](https://github.com/openfga/java-sdk/blob/main/docs/TypeDefinition.md)
- [TypeName](https://github.com/openfga/java-sdk/blob/main/docs/TypeName.md)
- [TypedWildcard](https://github.com/openfga/java-sdk/blob/main/docs/TypedWildcard.md)
- [UnauthenticatedResponse](https://github.com/openfga/java-sdk/blob/main/docs/UnauthenticatedResponse.md)
- [UnprocessableContentErrorCode](https://github.com/openfga/java-sdk/blob/main/docs/UnprocessableContentErrorCode.md)
- [UnprocessableContentMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/UnprocessableContentMessageResponse.md)
- [User](https://github.com/openfga/java-sdk/blob/main/docs/User.md)
- [UserTypeFilter](https://github.com/openfga/java-sdk/blob/main/docs/UserTypeFilter.md)
- [Users](https://github.com/openfga/java-sdk/blob/main/docs/Users.md)
- [Userset](https://github.com/openfga/java-sdk/blob/main/docs/Userset.md)
- [UsersetTree](https://github.com/openfga/java-sdk/blob/main/docs/UsersetTree.md)
- [UsersetTreeDifference](https://github.com/openfga/java-sdk/blob/main/docs/UsersetTreeDifference.md)
- [UsersetTreeTupleToUserset](https://github.com/openfga/java-sdk/blob/main/docs/UsersetTreeTupleToUserset.md)
- [UsersetUser](https://github.com/openfga/java-sdk/blob/main/docs/UsersetUser.md)
- [Usersets](https://github.com/openfga/java-sdk/blob/main/docs/Usersets.md)
- [ValidationErrorMessageResponse](https://github.com/openfga/java-sdk/blob/main/docs/ValidationErrorMessageResponse.md)
- [WriteAssertionsRequest](https://github.com/openfga/java-sdk/blob/main/docs/WriteAssertionsRequest.md)
- [WriteAuthorizationModelRequest](https://github.com/openfga/java-sdk/blob/main/docs/WriteAuthorizationModelRequest.md)
- [WriteAuthorizationModelResponse](https://github.com/openfga/java-sdk/blob/main/docs/WriteAuthorizationModelResponse.md)
- [WriteRequest](https://github.com/openfga/java-sdk/blob/main/docs/WriteRequest.md)
- [WriteRequestDeletes](https://github.com/openfga/java-sdk/blob/main/docs/WriteRequestDeletes.md)
- [WriteRequestWrites](https://github.com/openfga/java-sdk/blob/main/docs/WriteRequestWrites.md)
### OpenTelemetry
This SDK supports producing metrics that can be consumed as part of an [OpenTelemetry](https://opentelemetry.io/) setup. For more information, please see [the documentation](https://github.com/openfga/java-sdk/blob/main/docs/OpenTelemetry.md)
## Contributing
See [CONTRIBUTING](./CONTRIBUTING.md) for details.
## Author
[OpenFGA](https://github.com/openfga)
## License
This project is licensed under the Apache-2.0 license. See the [LICENSE](https://github.com/openfga/java-sdk/blob/main/LICENSE) file for more info.
The code in this repo was auto generated by [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) from a template based on the [Java template](https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator/src/main/resources/Java), licensed under the [Apache License 2.0](https://github.com/OpenAPITools/openapi-generator/blob/master/LICENSE).