An idiomatic Rust client library for SpiceDB, the open-source, Google Zanzibar-inspired authorization system.
- Type-safe: Wraps the SpiceDB gRPC API with idiomatic Rust types — no raw protobufs
- Async-first: Built on tonic and tokio
- 3-state permissions:
PermissionResultcorrectly modelsAllowed,Denied, andConditional(caveated) outcomes - Streaming: All streaming RPCs return
impl Stream<Item = Result<T, Error>> - Shareable:
ClientisClone + Send + Sync— clone it freely across tasks - Feature-gated:
watch,experimental,serde, TLS backends
use prescience::{Client,ObjectReference,SubjectReference,Consistency,PermissionResult};#[tokio::main]asyncfnmain() -> Result<(), prescience::Error>{let client = Client::new("http://localhost:50051","my-token").await?;let result = client
.check_permission(&ObjectReference::new("document","doc-123")?,"view",&SubjectReference::new(ObjectReference::new("user","alice")?,None::<String>)?,).consistency(Consistency::FullyConsistent).await?;match result {PermissionResult::Allowed => println!("access granted"),PermissionResult::Denied => println!("access denied"),PermissionResult::Conditional{ missing_fields } => {println!("need caveat context: {:?}", missing_fields);}}Ok(())}use prescience::{Client,ObjectReference,SubjectReference,Relationship,RelationshipUpdate};
# asyncfnexample(client:&Client) -> Result<(), prescience::Error>{let token = client
.write_relationships(vec![RelationshipUpdate::create(Relationship::new(ObjectReference::new("document","doc-123")?,"viewer",SubjectReference::new(ObjectReference::new("user","bob")?,None::<String>)?,)),]).await?;// Use the token for subsequent readslet result = client
.check_permission(&ObjectReference::new("document","doc-123")?,"view",&SubjectReference::new(ObjectReference::new("user","bob")?,None::<String>)?,).consistency(prescience::Consistency::AtLeastAsFresh(token)).await?;
# Ok(())
# }use tokio_stream::StreamExt;
# asyncfnexample(client:&prescience::Client) -> Result<(), prescience::Error>{let subject = prescience::SubjectReference::new(
prescience::ObjectReference::new("user","alice")?,None::<String>,)?;letmut stream = client
.lookup_resources("document","view",&subject).consistency(prescience::Consistency::FullyConsistent).send().await?;whileletSome(result) = stream.next().await{let item = result?;println!("resource: {}, permission: {:?}", item.resource_id, item.permission);}
# Ok(())
# }| Feature | Default | Description |
|---|---|---|
watch | No | WatchService for streaming relationship changes |
experimental | No | Bulk APIs: BulkCheckPermission, BulkImport/Export |
serde | No | Serialize/Deserialize on ZedToken and domain types |
tls-rustls | No | Use rustls for TLS |
tls-native | No | Use native/system TLS |
All methods return Result<T, prescience::Error>. The error type provides:
- Structured matching:
Error::Transport,Error::Status,Error::InvalidArgument, etc. - Retryability:
error.is_retryable()returnstrueforUNAVAILABLEandDEADLINE_EXCEEDED - gRPC code access:
error.code()returns the gRPC status code
This project uses devenv for a reproducible development environment:
# Enter the dev shell (provides Rust, protoc, SpiceDB)
devenv shell
# Build
cargo build --all-features
# Test
cargo test --all-features
# Lint
cargo clippy --all-features -- -D warnings
# Start a local SpiceDB for integration testing
spicedb serve --grpc-preshared-key "test-key" --datastore-engine memoryApache-2.0