1pub mod account_management;
2pub mod admin;
3pub mod api_key;
4pub mod device_authorization;
5pub mod email_password;
6pub mod email_verification;
7pub mod helpers;
8pub mod oauth;
9pub mod organization;
10pub mod passkey;
11pub mod password_management;
12pub mod session_management;
13pub mod two_factor;
14pub mod user_management;
15
16use serde::{Deserialize, Serialize};
17
18#[derive(Debug, Serialize, Deserialize)]
19pub(crate) struct StatusResponse {
20 status: bool,
21}
22
23#[cfg(test)]
24pub(crate) mod test_helpers {
25 use std::collections::HashMap;
26 use std::sync::Arc;
27
28 use better_auth_core::config::AuthConfig;
29 use better_auth_core::wire::{SessionView, UserView};
30 use better_auth_core::{AuthContext, AuthRequest, CreateSession, CreateUser, HttpMethod};
31 use better_auth_seaorm::store::__private_test_support::bundled_schema::BundledSchema;
32 use better_auth_seaorm::{Database, SeaOrmStore};
33 use chrono::{Duration, Utc};
34
35 pub type TestDatabase = dyn better_auth_core::store::AuthStore<BundledSchema>;
36
37 pub fn create_test_config() -> AuthConfig {
38 AuthConfig::new("test-secret-key-at-least-32-chars-long")
39 }
40
41 pub async fn create_test_database() -> Arc<TestDatabase> {
42 let database = Database::connect("sqlite::memory:")
43 .await
44 .expect("sqlite test database should connect");
45 better_auth_seaorm::store::__private_test_support::migrator::run_migrations(&database)
46 .await
47 .expect("sqlite test migrations should run");
48 Arc::new(SeaOrmStore::<BundledSchema>::new(
49 Arc::new(create_test_config()),
50 database,
51 ))
52 }
53
54 pub async fn create_test_context() -> AuthContext<BundledSchema> {
55 create_test_context_with_config(create_test_config()).await
56 }
57
58 pub fn create_test_context_blocking() -> AuthContext<BundledSchema> {
59 tokio::runtime::Builder::new_current_thread()
60 .enable_all()
61 .build()
62 .expect("test runtime should build")
63 .block_on(create_test_context())
64 }
65
66 pub async fn create_test_context_with_config(config: AuthConfig) -> AuthContext<BundledSchema> {
67 let config = Arc::new(config);
68 let database = create_test_database().await;
69 AuthContext::new(config, database)
70 }
71
72 pub async fn create_user(
73 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
74 create_user: CreateUser,
75 ) -> UserView {
76 let user = ctx.database.create_user(create_user).await.unwrap();
77 UserView::from(&user)
78 }
79
80 pub async fn create_session(
81 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
82 user_id: String,
83 expires_in: Duration,
84 ) -> SessionView {
85 let create_session = CreateSession {
86 user_id,
87 expires_at: Utc::now() + expires_in,
88 ip_address: Some("127.0.0.1".to_string()),
89 user_agent: Some("test-agent".to_string()),
90 impersonated_by: None,
91 active_organization_id: None,
92 };
93 let session = ctx.database.create_session(create_session).await.unwrap();
94 SessionView::from(&session)
95 }
96
97 pub async fn create_user_and_session(
98 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
99 user_data: CreateUser,
100 session_expires_in: Duration,
101 ) -> (UserView, SessionView) {
102 let user = create_user(ctx, user_data).await;
103 let session = create_session(ctx, user.id.clone(), session_expires_in).await;
104 (user, session)
105 }
106
107 pub async fn create_test_context_with_user(
108 create_user: CreateUser,
109 session_expires_in: Duration,
110 ) -> (AuthContext<BundledSchema>, UserView, SessionView) {
111 let ctx = create_test_context().await;
112 let (user, session) = create_user_and_session(&ctx, create_user, session_expires_in).await;
113 (ctx, user, session)
114 }
115
116 pub fn create_auth_request(
117 method: HttpMethod,
118 path: &str,
119 token: Option<&str>,
120 body: Option<Vec<u8>>,
121 query: HashMap<String, String>,
122 ) -> AuthRequest {
123 let mut headers = HashMap::new();
124 if let Some(token) = token {
125 headers.insert("authorization".to_string(), format!("Bearer {}", token));
126 }
127
128 AuthRequest::from_parts(method, path.to_string(), headers, body, query)
129 }
130
131 pub fn create_auth_request_no_query(
132 method: HttpMethod,
133 path: &str,
134 token: Option<&str>,
135 body: Option<Vec<u8>>,
136 ) -> AuthRequest {
137 create_auth_request(method, path, token, body, HashMap::new())
138 }
139
140 pub fn create_auth_json_request_no_query(
141 method: HttpMethod,
142 path: &str,
143 token: Option<&str>,
144 body: Option<serde_json::Value>,
145 ) -> AuthRequest {
146 create_auth_json_request(method, path, token, body, HashMap::new())
147 }
148
149 pub fn create_auth_json_request(
150 method: HttpMethod,
151 path: &str,
152 token: Option<&str>,
153 body: Option<serde_json::Value>,
154 query: HashMap<String, String>,
155 ) -> AuthRequest {
156 let mut req = create_auth_request(
157 method,
158 path,
159 token,
160 body.map(|b| serde_json::to_vec(&b).unwrap()),
161 query,
162 );
163 req.headers
164 .insert("content-type".to_string(), "application/json".to_string());
165 req
166 }
167}
168
169pub use account_management::AccountManagementPlugin;
170pub use admin::{AdminConfig, AdminPlugin, RolePermissions};
171pub use api_key::{ApiKeyConfig, ApiKeyPlugin};
172pub use better_auth_core::PasswordHasher;
173pub use device_authorization::DeviceAuthorizationPlugin;
174pub use email_password::{EmailPasswordConfig, EmailPasswordPlugin};
175pub use email_verification::{
176 EmailVerificationConfig, EmailVerificationHook, EmailVerificationPlugin, SendVerificationEmail,
177};
178pub use organization::{OrganizationConfig, OrganizationPlugin};
179pub use passkey::{PasskeyConfig, PasskeyPlugin};
180pub use password_management::{
181 PasswordManagementConfig, PasswordManagementPlugin, SendResetPassword,
182};
183pub use session_management::SessionManagementPlugin;
184pub use two_factor::{SendTwoFactorOtp, TwoFactorConfig, TwoFactorPlugin};
185pub use user_management::{
186 ChangeEmailConfig, DeleteUserConfig, UserManagementConfig, UserManagementPlugin,
187};