beep_authz/lib.rs
1//! # beep-authz
2//!
3//! A Rust authorization library with SpiceDB integration for fine-grained permissions.
4//!
5//! This crate provides a high-level, type-safe interface to [SpiceDB](https://github.com/authzed/spicedb),
6//! a Google Zanzibar-inspired authorization system. It enables relationship-based access control
7//! (ReBAC) for your Rust applications with minimal boilerplate.
8//!
9//! ## Features
10//!
11//! - **SpiceDB Integration** - Native support for SpiceDB/AuthZed with gRPC
12//! - **Type Safety** - Strongly-typed permissions and objects
13//! - **Async/Await** - Built on Tokio for high-performance async operations
14//! - **Easy to Use** - Simple API for checking permissions
15//!
16//! ## Quick Start
17//!
18//! ```no_run
19//! use authz::{SpiceDbRepository, SpiceDbConfig, SpiceDbObject, Permissions};
20//!
21//! #[tokio::main]
22//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
23//! // Configure connection to SpiceDB
24//! let config = SpiceDbConfig {
25//! endpoint: "localhost:50051".to_string(),
26//! token: Some("your-preshared-key".to_string()),
27//! };
28//!
29//! // Create repository
30//! let authz = SpiceDbRepository::new(config).await?;
31//!
32//! // Check permissions
33//! let result = authz.check_permissions(
34//! SpiceDbObject::Channel("channel-123".to_string()),
35//! Permissions::ViewChannels,
36//! SpiceDbObject::User("user-456".to_string()),
37//! ).await;
38//!
39//! if result.has_permissions() {
40//! println!("Access granted!");
41//! } else {
42//! println!("Access denied!");
43//! }
44//!
45//! Ok(())
46//! }
47//! ```
48//!
49//! ## Permission Checking
50//!
51//! The main functionality is provided by [`SpiceDbRepository`], which offers two methods
52//! for checking permissions:
53//!
54//! - [`SpiceDbRepository::check_permissions`] - High-level, type-safe API
55//! - [`SpiceDbRepository::check_permissions_raw`] - Lower-level API for advanced use cases
56//!
57//! ## Permission Types
58//!
59//! The [`Permissions`] enum defines all available permission types:
60//!
61//! - Administrator, ManageServer, ManageRoles
62//! - CreateInvitation, ManageChannels, ManageWebhooks
63//! - ViewChannels, SendMessages, AttachFiles
64//! - ManageNicknames, ChangeNickname, ManageMessages
65//!
66//! ## Object Types
67//!
68//! The [`SpiceDbObject`] enum represents different resource types:
69//!
70//! - `Server` - A server/workspace
71//! - `Channel` - A communication channel
72//! - `User` - A user/subject
73//! - `PermissionOverride` - A permission override rule
74//!
75//! ## Configuration
76//!
77//! Configure your SpiceDB connection using [`SpiceDbConfig`], which supports:
78//! - Manual configuration
79//! - Environment variables (`SPICEDB_ENDPOINT`, `SPICEDB_TOKEN`)
80//! - Command-line arguments (via clap)
81//!
82//! ## Error Handling
83//!
84//! The crate defines [`AuthorizationError`] for authorization failures:
85//! - `Unauthorized` - Permission denied
86//! - `ConnectionError` - Failed to connect to SpiceDB
87//!
88//! ## Examples
89//!
90//! ### Checking Administrative Access
91//!
92//! ```no_run
93//! # use authz::{SpiceDbRepository, SpiceDbObject, Permissions};
94//! # async fn example(repo: SpiceDbRepository) {
95//! let is_admin = repo.check_permissions(
96//! SpiceDbObject::Server("my-server".to_string()),
97//! Permissions::Administrator,
98//! SpiceDbObject::User("user-123".to_string()),
99//! ).await.has_permissions();
100//!
101//! if is_admin {
102//! // Grant full access
103//! }
104//! # }
105//! ```
106//!
107//! ### Using Result for Error Propagation
108//!
109//! ```no_run
110//! # use authz::{SpiceDbRepository, SpiceDbObject, Permissions, AuthorizationError};
111//! # async fn example(repo: SpiceDbRepository) -> Result<(), AuthorizationError> {
112//! repo.check_permissions(
113//! SpiceDbObject::Channel("private".to_string()),
114//! Permissions::SendMessages,
115//! SpiceDbObject::User("user-456".to_string()),
116//! ).await.result()?;
117//!
118//! // Code here only runs if permission is granted
119//! println!("User can send messages");
120//! # Ok(())
121//! # }
122//! ```
123
124// Include the generated protobuf code
125pub mod google {
126 pub mod rpc {
127 tonic::include_proto!("google.rpc");
128 }
129}
130
131pub mod authzed {
132 pub mod api {
133 pub mod v1 {
134 tonic::include_proto!("authzed.api.v1");
135 }
136 }
137}
138
139// Re-export commonly used types for convenience
140pub use authzed::api::v1::{
141 experimental_service_client::ExperimentalServiceClient,
142 permissions_service_client::PermissionsServiceClient,
143 schema_service_client::SchemaServiceClient, watch_service_client::WatchServiceClient,
144};
145use thiserror::Error;
146
147/// Configuration module for SpiceDB connection settings.
148///
149/// Contains [`SpiceDbConfig`] for configuring endpoint and authentication.
150pub mod config;
151
152/// gRPC authentication interceptor for SpiceDB.
153///
154/// Internal module that handles token-based authentication for gRPC requests.
155pub mod grpc_auth;
156
157/// Object type definitions for SpiceDB resources.
158///
159/// Contains [`SpiceDbObject`] enum representing different resource types.
160pub mod object;
161
162/// Permission types and authorization result handling.
163///
164/// Contains [`Permissions`] enum and [`AuthorizationResult`] for working with
165/// permission check results.
166pub mod permission;
167
168/// SpiceDB repository and client implementation.
169///
170/// Contains [`SpiceDbRepository`] which provides the main API for checking permissions.
171pub mod spicedb;
172
173// Re-export main types for convenience
174pub use config::SpiceDbConfig;
175pub use object::SpiceDbObject;
176pub use permission::{AuthorizationResult, Permissions};
177pub use spicedb::SpiceDbRepository;
178
179/// Errors that can occur during authorization operations.
180///
181/// # Variants
182///
183/// - [`Unauthorized`](AuthorizationError::Unauthorized) - The subject does not have permission to access the resource
184/// - [`ConnectionError`](AuthorizationError::ConnectionError) - Failed to establish or maintain connection to SpiceDB
185#[derive(Debug, Error)]
186pub enum AuthorizationError {
187 /// The subject is not allowed to access the requested resource.
188 ///
189 /// This error is returned when a permission check fails, indicating that
190 /// the subject does not have the necessary permission on the resource.
191 #[error("You are not allowed to access this resource")]
192 Unauthorized,
193
194 /// Failed to connect to the SpiceDB server.
195 ///
196 /// This error occurs when the gRPC connection to SpiceDB cannot be established
197 /// or when communication fails.
198 #[error("Could not connect to spice db: {msg}")]
199 ConnectionError {
200 /// Details about the connection failure
201 msg: String,
202 },
203}