systemprompt_traits/
auth.rs1use async_trait::async_trait;
10use std::sync::Arc;
11use systemprompt_identifiers::UserId;
12
13pub type AuthResult<T> = Result<T, AuthProviderError>;
14
15#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum AuthProviderError {
18 #[error("Invalid credentials")]
19 InvalidCredentials,
20
21 #[error("User not found")]
22 UserNotFound,
23
24 #[error("Invalid token")]
25 InvalidToken,
26
27 #[error("Token expired")]
28 TokenExpired,
29
30 #[error("Insufficient permissions")]
31 InsufficientPermissions,
32
33 #[error("Internal error: {0}")]
34 Internal(String),
35}
36
37#[derive(Debug, Clone)]
38pub struct AuthUser {
39 pub id: UserId,
40 pub name: String,
41 pub email: String,
42 pub roles: Vec<String>,
43 pub is_active: bool,
44}
45
46#[derive(Debug, Clone, Default)]
53pub struct FederatedIdentityClaims {
54 pub email: Option<String>,
55 pub email_verified: bool,
56 pub name: Option<String>,
57 pub preferred_username: Option<String>,
58 pub roles: Vec<String>,
59}
60
61#[derive(Debug, Clone, Default)]
70pub enum SenderIdentity {
71 Linked(FederatedIdentityClaims),
72 #[default]
73 Unlinked,
74}
75
76impl SenderIdentity {
77 #[must_use]
78 pub fn claims(&self) -> FederatedIdentityClaims {
79 match self {
80 Self::Linked(claims) => claims.clone(),
81 Self::Unlinked => FederatedIdentityClaims::default(),
82 }
83 }
84}
85
86#[async_trait]
87pub trait UserProvider: Send + Sync {
88 async fn find_by_id(&self, id: &UserId) -> AuthResult<Option<AuthUser>>;
89 async fn find_by_email(&self, email: &str) -> AuthResult<Option<AuthUser>>;
90 async fn find_by_name(&self, name: &str) -> AuthResult<Option<AuthUser>>;
91 async fn create_user(
92 &self,
93 name: &str,
94 email: &str,
95 full_name: Option<&str>,
96 ) -> AuthResult<AuthUser>;
97 async fn create_anonymous(&self, fingerprint: &str) -> AuthResult<AuthUser>;
98 async fn assign_roles(&self, user_id: &UserId, roles: &[String]) -> AuthResult<()>;
99
100 async fn find_or_create_federated(
101 &self,
102 issuer: &str,
103 external_sub: &str,
104 claims: &FederatedIdentityClaims,
105 ) -> AuthResult<UserId>;
106
107 async fn promote_anonymous(&self, source: &UserId, target: &UserId) -> AuthResult<u64>;
108}
109
110#[async_trait]
111pub trait RoleProvider: Send + Sync {
112 async fn get_roles(&self, user_id: &UserId) -> AuthResult<Vec<String>>;
113 async fn assign_role(&self, user_id: &UserId, role: &str) -> AuthResult<()>;
114 async fn revoke_role(&self, user_id: &UserId, role: &str) -> AuthResult<()>;
115 async fn list_users_by_role(&self, role: &str) -> AuthResult<Vec<AuthUser>>;
116}
117
118pub type DynUserProvider = Arc<dyn UserProvider>;
119pub type DynRoleProvider = Arc<dyn RoleProvider>;