1pub mod account_management;
2pub mod admin;
3pub mod anonymous;
4pub mod api_key;
5pub mod captcha;
6pub mod custom_session;
7pub mod device_authorization;
8pub mod email_otp;
9pub mod email_password;
10pub mod email_verification;
11pub mod endpoint_context;
12pub mod have_i_been_pwned;
13pub mod helpers;
14mod json_body;
15pub mod jwt;
16pub mod last_login_method;
17pub mod magic_link;
18pub mod multi_session;
19pub mod oauth;
20pub mod one_tap;
21pub mod one_time_token;
22pub mod open_api;
23pub mod organization;
24pub mod passkey;
25pub mod password_management;
26pub mod phone_number;
27mod query_input;
28pub mod session_management;
29mod session_update;
30pub mod siwe;
31mod symmetric;
32pub mod test_utils;
33pub mod two_factor;
34pub mod user_management;
35pub mod username;
36
37use serde::{Deserialize, Serialize};
38
39#[derive(Debug, Serialize, Deserialize)]
40pub(crate) struct StatusResponse {
41 status: bool,
42}
43
44#[cfg(test)]
45pub(crate) mod test_helpers {
46 use std::collections::HashMap;
47 use std::sync::Arc;
48
49 use better_auth_core::config::AuthConfig;
50 use better_auth_core::wire::{SessionView, UserView};
51 use better_auth_core::{AuthContext, AuthRequest, CreateSession, CreateUser, HttpMethod};
52 use better_auth_seaorm::store::__private_test_support::bundled_schema::BundledSchema;
53 use better_auth_seaorm::{Database, SeaOrmStore};
54 use chrono::{Duration, Utc};
55
56 pub type TestDatabase = dyn better_auth_core::store::AuthStore<BundledSchema>;
57
58 pub fn finalize_response(
60 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
61 req: &AuthRequest,
62 mut response: better_auth_core::AuthResponse,
63 ) -> better_auth_core::AuthResponse {
64 ctx.session_manager()
65 .finish_response(req, &mut response)
66 .expect("endpoint response should finalize");
67 response
68 }
69
70 pub fn create_test_config() -> AuthConfig {
71 let mut config = AuthConfig::new("test-secret-key-at-least-32-chars-long")
72 .base_url("http://localhost:3000");
73 config.session.bearer = Some(better_auth_core::config::BearerConfig::default());
74 config
75 }
76
77 pub async fn create_test_database() -> Arc<TestDatabase> {
78 let database = Database::connect("sqlite::memory:")
79 .await
80 .expect("sqlite test database should connect");
81 better_auth_seaorm::store::__private_test_support::migrator::run_migrations(&database)
82 .await
83 .expect("sqlite test migrations should run");
84 Arc::new(SeaOrmStore::<BundledSchema>::new(
85 Arc::new(create_test_config()),
86 database,
87 ))
88 }
89
90 pub async fn create_test_context() -> AuthContext<BundledSchema> {
91 create_test_context_with_config(create_test_config()).await
92 }
93
94 pub fn create_test_context_blocking() -> AuthContext<BundledSchema> {
95 tokio::runtime::Builder::new_current_thread()
96 .enable_all()
97 .build()
98 .expect("test runtime should build")
99 .block_on(create_test_context())
100 }
101
102 pub async fn create_test_context_with_config(config: AuthConfig) -> AuthContext<BundledSchema> {
103 let config = Arc::new(config);
104 let database = create_test_database().await;
105 AuthContext::new(config, database)
106 .initialize_request_context()
107 .await
108 .expect("test request context should initialize")
109 .as_ref()
110 .clone()
111 }
112
113 pub async fn create_user(
114 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
115 create_user: CreateUser,
116 ) -> UserView {
117 let user = ctx.database.create_user(create_user).await.unwrap();
118 UserView::from(&user)
119 }
120
121 pub async fn create_session(
122 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
123 user_id: String,
124 expires_in: Duration,
125 ) -> SessionView {
126 let create_session = CreateSession {
127 additional_fields: Default::default(),
128 user_id: user_id.into(),
129 expires_at: (Utc::now() + expires_in).into(),
130 ip_address: Some("127.0.0.1".to_string()),
131 user_agent: Some("test-agent".to_string()),
132 impersonated_by: None,
133 active_organization_id: None,
134 };
135 let session = ctx.database.create_session(create_session).await.unwrap();
136 SessionView::from(&session)
137 }
138
139 pub async fn create_user_and_session(
140 ctx: &AuthContext<impl better_auth_core::AuthSchema>,
141 user_data: CreateUser,
142 session_expires_in: Duration,
143 ) -> (UserView, SessionView) {
144 let user = create_user(ctx, user_data).await;
145 let session =
146 create_session(ctx, user.id.typed().unwrap().clone(), session_expires_in).await;
147 (user, session)
148 }
149
150 pub async fn create_test_context_with_user(
151 create_user: CreateUser,
152 session_expires_in: Duration,
153 ) -> (AuthContext<BundledSchema>, UserView, SessionView) {
154 let ctx = create_test_context().await;
155 let (user, session) = create_user_and_session(&ctx, create_user, session_expires_in).await;
156 (ctx, user, session)
157 }
158
159 pub fn create_auth_request(
160 method: HttpMethod,
161 path: &str,
162 token: Option<&str>,
163 body: Option<Vec<u8>>,
164 query: HashMap<String, String>,
165 ) -> AuthRequest {
166 let mut headers = HashMap::new();
167 if let Some(token) = token {
168 headers.insert("authorization".to_string(), format!("Bearer {}", token));
169 }
170
171 AuthRequest::from_parts(
172 method,
173 path.to_string(),
174 headers,
175 body,
176 Some(serde_json::json!(query)),
177 )
178 }
179
180 pub fn create_auth_request_no_query(
181 method: HttpMethod,
182 path: &str,
183 token: Option<&str>,
184 body: Option<Vec<u8>>,
185 ) -> AuthRequest {
186 create_auth_request(method, path, token, body, HashMap::new())
187 }
188
189 pub fn create_auth_json_request_no_query(
190 method: HttpMethod,
191 path: &str,
192 token: Option<&str>,
193 body: Option<serde_json::Value>,
194 ) -> AuthRequest {
195 create_auth_json_request(method, path, token, body, HashMap::new())
196 }
197
198 pub fn create_auth_json_request(
199 method: HttpMethod,
200 path: &str,
201 token: Option<&str>,
202 body: Option<serde_json::Value>,
203 query: HashMap<String, String>,
204 ) -> AuthRequest {
205 let mut req = create_auth_request(
206 method,
207 path,
208 token,
209 body.map(|b| serde_json::to_vec(&b).unwrap()),
210 query,
211 );
212 req.headers
213 .insert("content-type".to_string(), "application/json".to_string());
214 req
215 }
216}
217
218pub use account_management::AccountManagementPlugin;
219pub use admin::{AdminConfig, AdminPlugin, RolePermissions};
220pub use api_key::{ApiKeyConfig, ApiKeyPlugin};
221pub use better_auth_core::PasswordHasher;
222pub use custom_session::{CustomSessionCallback, CustomSessionInput, CustomSessionPlugin};
223pub use device_authorization::DeviceAuthorizationPlugin;
224pub use email_otp::{
225 EmailOtpApi, EmailOtpCodec, EmailOtpConfig, EmailOtpGenerator, EmailOtpMessage, EmailOtpPlugin,
226 EmailOtpStorage, EmailOtpType, SendEmailOtp,
227};
228pub use email_password::{EmailPasswordConfig, EmailPasswordPlugin};
229pub use email_verification::{
230 EmailVerificationConfig, EmailVerificationHook, EmailVerificationPlugin, SendVerificationEmail,
231};
232pub use jwt::{
233 JwtAdapterFuture, JwtAlgorithm, JwtApi, JwtAudience, JwtCallOverrides, JwtCallbackFuture,
234 JwtCallbacks, JwtCustomSign, JwtDefinePayload, JwtExpiration, JwtGetSubject, JwtKeyOptions,
235 JwtKeyPairConfig, JwtPlugin, JwtPluginConfig, JwtSigningOptions, JwtTokenOptions,
236};
237pub use magic_link::{MagicLinkConfig, MagicLinkMessage, MagicLinkPlugin, SendMagicLink};
238pub use multi_session::{MultiSessionConfig, MultiSessionPlugin};
239pub use oauth::{OAuthPopupPlugin, OAuthProxyConfig, OAuthProxyPlugin};
240pub use one_tap::{OneTapConfig, OneTapPlugin};
241pub use one_time_token::{OneTimeTokenConfig, OneTimeTokenPlugin, TokenStorage};
242pub use open_api::{OpenApiConfig, OpenApiPlugin};
243pub use organization::{OrganizationConfig, OrganizationPlugin};
244pub use passkey::{PasskeyConfig, PasskeyPlugin};
245pub use password_management::{
246 PasswordManagementConfig, PasswordManagementPlugin, SendResetPassword,
247};
248pub use session_management::SessionManagementPlugin;
249pub use two_factor::{SendTwoFactorOtp, TwoFactorConfig, TwoFactorPlugin};
250pub use user_management::{
251 ChangeEmailConfig, DeleteUserConfig, UserManagementConfig, UserManagementPlugin,
252};
253
254pub mod user_admission;
255
256pub use last_login_method::{
257 BeforeStoreLastLoginCookie, LastLoginMethodConfig, LastLoginMethodPlugin,
258 LastLoginMethodResolver,
259};