The Authorization API is the core of InferaDB's SDK, providing permission checks, relationship management, lookups, and real-time change streaming.
let org = client.organization("org_...");
let vault = org.vault("vlt_...");let allowed = vault.check("user:alice", "view", "doc:1").await?;
if allowed {
// Grant access
}Add attribute-based context to permission checks for fine-grained access control:
let allowed = vault.check("user:alice", "view", "doc:confidential")
.with_context(Context::new()
.with("ip_address", "10.0.0.50")
.with("mfa_verified", true)
.with("department", "engineering"))
.await?;Context values are evaluated against conditions defined in your authorization schema.
Use require() when denial should be an error (e.g., in middleware):
vault.check("user:alice", "edit", "doc:1").require().await?;
// If denied, returns Err(AccessDenied)Check multiple permissions efficiently in a single request:
let results = vault.check_batch([
("user:alice", "view", "doc:1"),
("user:alice", "edit", "doc:1"),
("user:alice", "delete", "doc:1"),
]).await?;
// Results maintain input order
for (i, allowed) in results.iter().enumerate() {
println!("Check {}: {}", i, allowed);
}
// Convenience methods
if results.all_allowed() {
// All permissions granted
}
let denied = results.denied_indices();For read-after-write consistency, use consistency tokens:
// Write returns a token
let token = vault.relationships()
.write(Relationship::new("doc:1", "viewer", "user:alice"))
.await?;
// Use token for consistent read
let allowed = vault.check("user:alice", "view", "doc:1")
.at_least_as_fresh(token)
.await?;vault.relationships()
.write(Relationship::new("document:readme", "viewer", "user:alice"))
.await?;vault.relationships().write_batch([
Relationship::new("folder:docs", "viewer", "group:engineering#member"),
Relationship::new("document:readme", "parent", "folder:docs"),
]).await?;let rels = vault.relationships()
.list()
.resource("document:readme")
.collect()
.await?;
for rel in rels {
println!("{} -> {} -> {}", rel.resource(), rel.relation(), rel.subject());
}Filter by relation or subject:
let viewers = vault.relationships()
.list()
.resource("document:readme")
.relation("viewer")
.collect()
.await?;vault.relationships()
.delete(Relationship::new("document:readme", "viewer", "user:alice"))
.await?;Delete all relationships matching a filter:
vault.relationships()
.delete_where()
.resource("document:readme")
.execute()
.await?;Filter by relation or subject:
vault.relationships()
.delete_where()
.resource("document:readme")
.relation("viewer")
.subject("user:alice")
.execute()
.await?;Find all resources a subject can access:
let docs = vault.resources()
.accessible_by("user:alice")
.with_permission("view")
.resource_type("document")
.collect()
.await?;
for doc in docs {
println!("Alice can view: {}", doc);
}Find all subjects that have access to a resource:
let users = vault.subjects()
.with_permission("view")
.on_resource("document:readme")
.collect()
.await?;
for user in users {
println!("{} can view document:readme", user);
}Filter by subject type:
let groups = vault.subjects()
.with_permission("view")
.on_resource("document:readme")
.subject_type("group")
.collect()
.await?;Understand why access was allowed or denied:
let explanation = vault.explain_permission()
.subject("user:alice")
.permission("edit")
.resource("document:readme")
.execute()
.await?;
println!("{}", explanation.summary());
if explanation.allowed {
// Show the path that granted access
for node in &explanation.path {
println!(" via {} on {}", node.relation, node.resource);
}
} else {
// Show why access was denied
println!("Denied: {:?}", explanation.reason);
}Test hypothetical changes without modifying data:
let result = vault.simulate()
.add_relationship(Relationship::new("doc:1", "editor", "user:bob"))
.check("user:bob", "edit", "doc:1")
.await?;
if result.allowed {
println!("Adding this relationship would grant access");
}Simulate multiple changes:
let result = vault.simulate()
.add_relationship(Relationship::new("folder:docs", "viewer", "user:bob"))
.add_relationship(Relationship::new("doc:1", "parent", "folder:docs"))
.remove_relationship(Relationship::new("doc:1", "viewer", "user:alice"))
.check("user:bob", "view", "doc:1")
.await?;Stream real-time relationship changes:
use futures::StreamExt;
let mut stream = vault.watch()
.filter(WatchFilter::resource_type("document"))
.run()
.await?;
while let Some(event) = stream.next().await {
let event = event?;
println!("{}: {} {} {}",
event.operation, event.resource, event.relation, event.subject);
}// Filter by resource type
.filter(WatchFilter::resource_type("document"))
// Filter by specific resource
.filter(WatchFilter::resource("document:readme"))
// Filter by relation
.filter(WatchFilter::relation("viewer"))
// Filter by operation type
.filter(WatchFilter::operations([Operation::Create, Operation::Delete]))
// Combine multiple filters
.filter(WatchFilter::resource_type("document"))
.filter(WatchFilter::relation("editor"))For reliable processing, use resumable streams with revision tracking:
let mut stream = vault.watch()
.from_revision(last_processed_revision)
.resumable()
.run()
.await?;Permission checks return Ok(false) for denial, not errors:
match vault.check("user:alice", "view", "doc:1").await {
Ok(true) => println!("Access granted"),
Ok(false) => println!("Access denied"),
Err(e) => println!("Error: {}", e), // Network, auth, etc.
}Use require() when you want denial to be an error:
vault.check("user:alice", "view", "doc:1")
.require()
.await?; // Returns Err(AccessDenied) if denied- Error Handling - Detailed error handling patterns
- Testing - MockClient and InMemoryClient for testing
- Consistency - Consistency tokens and guarantees
- Integration Patterns - Framework middleware examples