SpiceDbRepository

Struct SpiceDbRepository 

Source
pub struct SpiceDbRepository { /* private fields */ }
Expand description

Main SpiceDB client for performing authorization checks.

SpiceDbRepository provides a high-level interface to interact with SpiceDB, a Google Zanzibar-inspired authorization system. It handles connection management, authentication, and permission checking operations.

§Architecture

The repository maintains a gRPC connection to a SpiceDB server and provides methods to check whether a subject (e.g., a user) has a specific permission on a resource (e.g., a channel or server).

§Examples

use authz::{SpiceDbRepository, SpiceDbConfig, SpiceDbObject, Permissions};

let config = SpiceDbConfig {
    endpoint: "localhost:50051".to_string(),
    token: Some("your-token".to_string()),
};

let repo = SpiceDbRepository::new(config).await?;

// Check if user can view a channel
let result = repo.check_permissions(
    SpiceDbObject::Channel("channel-123".to_string()),
    Permissions::ViewChannels,
    SpiceDbObject::User("user-456".to_string()),
).await;

if result.has_permissions() {
    println!("Access granted!");
}

Implementations§

Source§

impl SpiceDbRepository

Source

pub async fn new(config: SpiceDbConfig) -> Result<Self, AuthorizationError>

Creates a new SpiceDB client with the given configuration.

This establishes a gRPC connection to the SpiceDB server and sets up authentication using the provided token.

§Arguments
  • config - Configuration containing the endpoint URL and optional authentication token
§Returns

Returns Ok(SpiceDbRepository) on successful connection, or an AuthorizationError::ConnectionError if the connection fails.

§Examples
use authz::{SpiceDbRepository, SpiceDbConfig};

let config = SpiceDbConfig {
    endpoint: "localhost:50051".to_string(),
    token: Some("somerandomkey".to_string()),
};

let repo = SpiceDbRepository::new(config).await?;
§Errors

This function will return an error if:

  • The endpoint URL is invalid
  • The connection to SpiceDB cannot be established
  • Network issues prevent communication with the server
Source

pub async fn check_permissions( &self, resource: impl Into<SpiceDbObject>, permission: Permissions, subject: impl Into<SpiceDbObject>, ) -> AuthorizationResult

Checks if a subject has a specific permission on a resource.

This is the primary method for performing authorization checks in your application. It evaluates whether the given subject (e.g., a user) has the specified permission on the target resource (e.g., a channel, server, or other object).

§How It Works

The method performs the following steps:

  1. Converts the resource and subject into SpiceDB object references
  2. Sends a gRPC CheckPermission request to SpiceDB
  3. SpiceDB evaluates the permission based on defined relationships and rules
  4. Returns an AuthorizationResult indicating whether access is granted
§Arguments
  • resource - The resource being accessed (e.g., SpiceDbObject::Channel("123"))
  • permission - The permission being checked (e.g., Permissions::ViewChannels)
  • subject - The entity requesting access (e.g., SpiceDbObject::User("456"))
§Returns

Returns an AuthorizationResult which can be queried with:

  • has_permissions() - Returns true if access is granted
  • result() - Returns Ok(()) if granted, or Err(AuthorizationError) if denied
§Examples
§Basic permission check
use authz::{SpiceDbRepository, SpiceDbObject, Permissions};

let result = repo.check_permissions(
    SpiceDbObject::Channel("general".to_string()),
    Permissions::SendMessages,
    SpiceDbObject::User("alice".to_string()),
).await;

if result.has_permissions() {
    // Allow user to send message
    println!("User can send messages");
} else {
    // Deny access
    println!("User cannot send messages");
}
§Using result() for error handling
use authz::{SpiceDbRepository, SpiceDbObject, Permissions, AuthorizationError};

let result = repo.check_permissions(
    SpiceDbObject::Server("server-1".to_string()),
    Permissions::ManageRoles,
    SpiceDbObject::User("bob".to_string()),
).await;

// Returns error if permission denied
result.result()?;

// Continue with authorized action
println!("User is authorized to manage roles");
§Checking administrative access
use authz::{SpiceDbRepository, SpiceDbObject, Permissions};

let is_admin = repo.check_permissions(
    SpiceDbObject::Server("my-server".to_string()),
    Permissions::Administrator,
    SpiceDbObject::User("charlie".to_string()),
).await.has_permissions();

if is_admin {
    // Grant full access
}
§Performance Considerations

Each call to this method makes a network request to SpiceDB. For high-performance scenarios, consider:

  • Caching authorization results when appropriate
  • Batching multiple checks when possible
  • Using SpiceDB’s consistency guarantees to balance freshness vs. performance
§See Also
Source

pub async fn check_permissions_raw( &self, resource: impl Into<ObjectReference>, permission: impl Into<String>, subject: impl Into<ObjectReference>, ) -> Result<Permissionship, AuthorizationError>

Performs a raw permission check using SpiceDB object references and string permissions.

This is a lower-level API that provides more flexibility than check_permissions. It allows you to specify permissions as strings and use custom object references directly, which can be useful for:

  • Custom permission types not defined in the Permissions enum
  • Dynamic permission names determined at runtime
  • Direct integration with SpiceDB’s native types
§Arguments
  • resource - The resource object reference (must implement Into<ObjectReference>)
  • permission - The permission name as a string (e.g., “view”, “edit”, “admin”)
  • subject - The subject object reference (must implement Into<ObjectReference>)
§Returns

Returns a Result containing:

  • Ok(Permissionship) - The permission status from SpiceDB:
    • Permissionship::HasPermission - Access is granted
    • Permissionship::NoPermission - Access is denied
    • Permissionship::ConditionalPermission - Access depends on additional context
  • Err(AuthorizationError::Unauthorized) - The check failed or was denied
§Examples
§Custom permission check
use authz::{SpiceDbRepository, authzed::api::v1::ObjectReference};

let resource = ObjectReference {
    object_type: "document".to_string(),
    object_id: "doc-123".to_string(),
};

let subject = ObjectReference {
    object_type: "user".to_string(),
    object_id: "user-456".to_string(),
};

let permissionship = repo.check_permissions_raw(
    resource,
    "edit",
    subject,
).await?;

match permissionship {
    authz::authzed::api::v1::check_permission_response::Permissionship::HasPermission => {
        println!("Permission granted");
    }
    _ => {
        println!("Permission denied");
    }
}
§Dynamic permission names
use authz::{SpiceDbRepository, SpiceDbObject};

let permission_name = format!("can_{}", action);

let result = repo.check_permissions_raw(
    SpiceDbObject::Channel(resource_id.to_string()),
    permission_name,
    SpiceDbObject::User(user_id.to_string()),
).await?;

Ok(result.has_permissions())
§Errors

This function will return an error if:

  • The gRPC connection to SpiceDB fails
  • The request times out
  • The permission check is denied (returns AuthorizationError::Unauthorized)
§See Also

Trait Implementations§

Source§

impl Clone for SpiceDbRepository

Source§

fn clone(&self) -> SpiceDbRepository

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more