Skip to main content

better_auth_core/
entity.rs

1//! Entity traits for the Better Auth framework.
2//!
3//! These traits define the interface that entity types must implement.
4//! The framework accesses entity fields through these trait methods,
5//! allowing users to define their own entity structs with custom field names
6//! and extra fields.
7//!
8//! Use `#[derive(AuthUser)]` etc. from `better-auth-derive` to auto-implement
9//! these traits, or implement them manually.
10
11use chrono::{DateTime, Utc};
12use serde::Serialize;
13
14use crate::types::InvitationStatus;
15
16/// Trait representing a user entity.
17///
18/// The framework reads user fields through these getters. Custom types
19/// must provide all framework fields and may have additional fields.
20pub trait AuthUser: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
21    fn id(&self) -> &str;
22    fn email(&self) -> Option<&str>;
23    fn name(&self) -> Option<&str>;
24    fn email_verified(&self) -> bool;
25    fn image(&self) -> Option<&str>;
26    fn created_at(&self) -> DateTime<Utc>;
27    fn updated_at(&self) -> DateTime<Utc>;
28    fn username(&self) -> Option<&str>;
29    fn display_username(&self) -> Option<&str>;
30    fn two_factor_enabled(&self) -> bool;
31    fn role(&self) -> Option<&str>;
32    fn banned(&self) -> bool;
33    fn ban_reason(&self) -> Option<&str>;
34    fn ban_expires(&self) -> Option<DateTime<Utc>>;
35    fn metadata(&self) -> &serde_json::Value;
36}
37
38/// Trait representing a session entity.
39pub trait AuthSession: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
40    fn id(&self) -> &str;
41    fn expires_at(&self) -> DateTime<Utc>;
42    fn token(&self) -> &str;
43    fn created_at(&self) -> DateTime<Utc>;
44    fn updated_at(&self) -> DateTime<Utc>;
45    fn ip_address(&self) -> Option<&str>;
46    fn user_agent(&self) -> Option<&str>;
47    fn user_id(&self) -> &str;
48    fn impersonated_by(&self) -> Option<&str>;
49    fn active_organization_id(&self) -> Option<&str>;
50    fn active(&self) -> bool;
51}
52
53/// Trait representing an account entity (OAuth provider linking).
54pub trait AuthAccount: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
55    fn id(&self) -> &str;
56    fn account_id(&self) -> &str;
57    fn provider_id(&self) -> &str;
58    fn user_id(&self) -> &str;
59    fn access_token(&self) -> Option<&str>;
60    fn refresh_token(&self) -> Option<&str>;
61    fn id_token(&self) -> Option<&str>;
62    fn access_token_expires_at(&self) -> Option<DateTime<Utc>>;
63    fn refresh_token_expires_at(&self) -> Option<DateTime<Utc>>;
64    fn scope(&self) -> Option<&str>;
65    fn password(&self) -> Option<&str>;
66    fn created_at(&self) -> DateTime<Utc>;
67    fn updated_at(&self) -> DateTime<Utc>;
68}
69
70/// Trait representing an organization entity.
71pub trait AuthOrganization: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
72    fn id(&self) -> &str;
73    fn name(&self) -> &str;
74    fn slug(&self) -> &str;
75    fn logo(&self) -> Option<&str>;
76    fn metadata(&self) -> Option<&serde_json::Value>;
77    fn created_at(&self) -> DateTime<Utc>;
78    fn updated_at(&self) -> DateTime<Utc>;
79}
80
81/// Trait representing an organization member entity.
82pub trait AuthMember: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
83    fn id(&self) -> &str;
84    fn organization_id(&self) -> &str;
85    fn user_id(&self) -> &str;
86    fn role(&self) -> &str;
87    fn created_at(&self) -> DateTime<Utc>;
88}
89
90/// Trait representing an invitation entity.
91pub trait AuthInvitation: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
92    fn id(&self) -> &str;
93    fn organization_id(&self) -> &str;
94    fn email(&self) -> &str;
95    fn role(&self) -> &str;
96    fn status(&self) -> &InvitationStatus;
97    fn inviter_id(&self) -> &str;
98    fn expires_at(&self) -> DateTime<Utc>;
99    fn created_at(&self) -> DateTime<Utc>;
100
101    /// Check if the invitation is still pending.
102    fn is_pending(&self) -> bool {
103        *self.status() == InvitationStatus::Pending
104    }
105
106    /// Check if the invitation has expired.
107    fn is_expired(&self) -> bool {
108        self.expires_at() < Utc::now()
109    }
110}
111
112/// Trait representing a verification token entity.
113pub trait AuthVerification: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
114    fn id(&self) -> &str;
115    fn identifier(&self) -> &str;
116    fn value(&self) -> &str;
117    fn expires_at(&self) -> DateTime<Utc>;
118    fn created_at(&self) -> DateTime<Utc>;
119    fn updated_at(&self) -> DateTime<Utc>;
120}
121
122/// Trait representing a two-factor authentication entity.
123pub trait AuthTwoFactor: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
124    fn id(&self) -> &str;
125    fn secret(&self) -> &str;
126    fn backup_codes(&self) -> Option<&str>;
127    fn user_id(&self) -> &str;
128}
129
130/// Trait representing a passkey entity.
131pub trait AuthPasskey: Clone + Send + Sync + Serialize + std::fmt::Debug + 'static {
132    fn id(&self) -> &str;
133    fn name(&self) -> &str;
134    fn public_key(&self) -> &str;
135    fn user_id(&self) -> &str;
136    fn credential_id(&self) -> &str;
137    fn counter(&self) -> u64;
138    fn device_type(&self) -> &str;
139    fn backed_up(&self) -> bool;
140}
141
142/// Minimal user info for member-related API responses.
143///
144/// This is a concrete framework type (not generic) used to project
145/// user fields into member responses.
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct MemberUserView {
148    pub id: String,
149    pub email: Option<String>,
150    pub name: Option<String>,
151    pub image: Option<String>,
152}
153
154impl MemberUserView {
155    /// Construct from any type implementing [`AuthUser`].
156    pub fn from_user(user: &impl AuthUser) -> Self {
157        Self {
158            id: user.id().to_string(),
159            email: user.email().map(|s| s.to_string()),
160            name: user.name().map(|s| s.to_string()),
161            image: user.image().map(|s| s.to_string()),
162        }
163    }
164}
165
166use serde::Deserialize;