Expand description
§OpenFGA Rust Client
OpenFGA Rust Client is a type-safe client for OpenFGA with optional Authorization Model management and Authentication (Bearer or Client Credentials).
§Features
- Type-safe client for OpenFGA (gRPC) build on
tonic
- (JSON) Serialization and deserialization for Authorization Models in addition to protobuf Messages
- Uses
vendored-protoc
for well-known types - Rust files are pre-generated. - Optional Authorization Model management with Migration hooks. Ideal for stateless deployments. State is managed exclusively in OpenFGA. This enables fully automated model management by your Application without re-writing of Authorization Models on startup.
- Optional Authentication (Bearer or Client Credentials) via the Middle Crate. (Feature:
auth-middle
) - Convenience functions like
read_all_tuples
(handles pagination),get_store_by_name
and more.
§Usage
§Basic Usage
use openfga_client::client::OpenFgaServiceClient;
use tonic::transport::Channel;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint = "http://localhost:8081";
let service_client = OpenFgaServiceClient::connect(endpoint).await?;
// Use the client to interact with OpenFGA
Ok(())
}
§Bearer Token Authentication (API-Key)
use openfga_client::{client::BasicOpenFgaServiceClient, url};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint = url::Url::parse("http://localhost:8081")?;
let token = "your-bearer-token";
let service_client = BasicOpenFgaServiceClient::new_with_basic_auth(endpoint, token)?;
// Use the client to interact with OpenFGA
Ok(())
}
§Client Credential Authentication
use openfga_client::client::BasicOpenFgaServiceClient;
use url::Url;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint = Url::parse("http://localhost:8081")?;
let client_id = "your-client-id";
let client_secret = "your-client-secret";
let token_endpoint = Url::parse("http://localhost:8081/token")?;
let scopes = vec!["scope1", "scope2"];
let service_client = BasicOpenFgaServiceClient::new_with_client_credentials(endpoint, client_id, client_secret, token_endpoint, &scopes).await?;
// Use the client to interact with OpenFGA
Ok(())
}
§Authorization Model Management and Migration
For more details please check the TupleModelManager
.
Requires the following as part of the Authorization model:
type auth_model_id
type model_version
relations
define openfga_id: [auth_model_id]
define exists: [auth_model_id:*]
Usage:
use openfga_client::client::{OpenFgaServiceClient, TupleKeyWithoutCondition};
use openfga_client::migration::{AuthorizationModelVersion, MigrationFn, TupleModelManager};
use openfga_client::tonic::codegen::StdError;
#[allow(clippy::unused_async)]
async fn v1_1_migration(
client: OpenFgaServiceClient<tonic::transport::Channel>,
) -> std::result::Result<(), StdError> {
let _ = client;
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let endpoint = "http://localhost:8081";
let mut service_client = OpenFgaServiceClient::connect(endpoint).await?;
let store_name = "my-store";
let model_prefix = "my-model";
let mut manager = TupleModelManager::new(service_client.clone(), store_name, model_prefix)
// Migrations are executed in order for models that have not been previously migrated.
// First model - version 1.0
.add_model(
serde_json::from_str(include_str!("../tests/model-manager/v1.0/schema.json"))?,
AuthorizationModelVersion::new(1, 0),
// For major version upgrades, this is where tuple migrations go.
None::<MigrationFn<_>>,
None::<MigrationFn<_>>,
)
// Second model - version 1.1
.add_model(
serde_json::from_str(include_str!("../tests/model-manager/v1.1/schema.json"))?,
AuthorizationModelVersion::new(1, 1),
// For major version upgrades, this is where tuple migrations go.
Some(v1_1_migration),
None::<MigrationFn<_>>,
);
// Perform the migration if necessary
manager.migrate().await?;
let store_id = service_client
.get_store_by_name(store_name)
.await?
.expect("Store found")
.id;
let authorization_model_id = manager
.get_authorization_model_id(AuthorizationModelVersion::new(1, 1))
.await?
.expect("Authorization model found");
let client = service_client.into_client(&store_id, &authorization_model_id);
// Use the client.
// `store_id` and `authorization_model_id` are stored in the client and attached to all requests.
let page_size = 100;
let continuation_token = None;
let _tuples = client
.read(
page_size,
TupleKeyWithoutCondition {
user: "user:peter".to_string(),
relation: "owner".to_string(),
object: "organization:my-org".to_string(),
},
continuation_token,
)
.await?;
Ok(())
}
§License
This project is licensed under the Apache-2.0 License. See the LICENSE file for details.
§Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
Re-exports§
pub use prost_types;
pub use prost_wkt_types;
pub use tonic;
pub use url;