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