better_auth_core/plugin/
mod.rs1mod context;
2mod contracts;
3mod extensions;
4mod initialization;
5mod routes;
6
7use crate::config::AuthConfig;
8use crate::email::EmailProvider;
9use crate::entity::AuthSession;
10use crate::error::{AuthError, AuthResult};
11use crate::schema::AuthSchema;
12use crate::session::SessionManager;
13use crate::store::AuthStore;
14use crate::types::{AuthRequest, AuthResponse, HttpMethod};
15use async_trait::async_trait;
16pub use context::AuthContext;
17pub use contracts::AuthPlugin;
18pub use contracts::BeforeRequestAction;
19pub use contracts::HttpEndpointResponse;
20pub use contracts::HttpRequestAction;
21pub use contracts::VerificationEmailOverride;
22pub use contracts::VerificationEmailOverrideHandle;
23pub use extensions::ContextExtensions;
24pub use initialization::AuthInitContext;
25pub use initialization::AuthInitParts;
26pub use routes::AuthRoute;
27pub use routes::ResolvedEndpoint;
28use std::any::{Any, TypeId};
29use std::collections::HashMap;
30use std::sync::Arc;
31
32type MetadataMap = HashMap<String, serde_json::Value>;
33
34#[cfg(test)]
36mod tests {
37 use super::*;
38 use crate::entity::AuthUser;
39 use crate::test_store::test_database;
40
41 #[test]
43 fn auth_route_constructors() {
44 let get = AuthRoute::get("/test", "getTest");
45 assert_eq!(get.method, HttpMethod::Get);
46 assert_eq!(get.path, "/test");
47 assert_eq!(get.operation_id, "getTest");
48
49 let post = AuthRoute::post("/create", "createItem");
50 assert_eq!(post.method, HttpMethod::Post);
51
52 let put = AuthRoute::put("/update", "updateItem");
53 assert_eq!(put.method, HttpMethod::Put);
54
55 let delete = AuthRoute::delete("/remove", "deleteItem");
56 assert_eq!(delete.method, HttpMethod::Delete);
57 }
58
59 #[test]
61 fn auth_route_new() {
62 let route = AuthRoute::new(HttpMethod::Patch, "/patch", "patchIt");
63 assert_eq!(route.method, HttpMethod::Patch);
64 assert_eq!(route.path, "/patch");
65 }
66
67 #[test]
69 fn auth_context_new() {
70 let config = Arc::new(AuthConfig::new("test-secret-min-32-chars-1234567"));
71 let runtime = tokio::runtime::Runtime::new().expect("runtime should build");
72 let db = runtime.block_on(test_database());
73 let ctx = AuthContext::new(config, db);
74 assert!(ctx.email_provider.is_none());
75 assert!(ctx.metadata.is_empty());
76 }
77
78 #[test]
80 fn auth_context_metadata() {
81 let config = Arc::new(AuthConfig::new("test-secret-min-32-chars-1234567"));
82 let runtime = tokio::runtime::Runtime::new().expect("runtime should build");
83 let db = runtime.block_on(test_database());
84 let mut ctx = AuthContext::new(config, db);
85
86 ctx.set_metadata("key", serde_json::json!("value"));
87 assert_eq!(ctx.get_metadata("key"), Some(&serde_json::json!("value")));
88 assert!(ctx.get_metadata("missing").is_none());
89 }
90
91 #[test]
93 fn auth_context_email_provider_error_when_none() {
94 let config = Arc::new(AuthConfig::new("test-secret-min-32-chars-1234567"));
95 let runtime = tokio::runtime::Runtime::new().expect("runtime should build");
96 let db = runtime.block_on(test_database());
97 let ctx = AuthContext::new(config, db);
98 assert!(ctx.email_provider().is_err());
99 }
100
101 #[tokio::test]
103 async fn auth_context_require_session_unauthenticated() {
104 let config = Arc::new(AuthConfig::new("test-secret-min-32-chars-1234567"));
105 let db = test_database().await;
106 let ctx = AuthContext::new(config, db);
107 let req = AuthRequest::new(HttpMethod::Get, "/test");
108 let result = ctx.require_session(&req).await;
109 assert!(result.is_err());
110 }
111
112 #[tokio::test]
114 async fn auth_context_require_session_with_valid_session() {
115 let config = Arc::new(AuthConfig::new("test-secret-min-32-chars-1234567"));
116 let db = test_database().await;
117
118 let user = db
120 .create_user(crate::types::CreateUser::new().with_email("test@test.com"))
121 .await
122 .unwrap();
123
124 let sm = SessionManager::new(Arc::clone(&config), Arc::clone(&db));
126 let session = sm.create_session(&user, None, None).await.unwrap();
127
128 let ctx = AuthContext::new(Arc::clone(&config), db);
130 let mut req = AuthRequest::new(HttpMethod::Get, "/test");
131 drop(req.headers.insert(
132 "cookie".into(),
133 format!(
134 "better-auth.session_token={}",
135 crate::utils::cookie_utils::sign_cookie_value(session.token(), &config.secret)
136 ),
137 ));
138
139 let (found_user, _found_session) = ctx.require_session(&req).await.unwrap();
140 assert_eq!(found_user.id(), user.id());
141 }
142}
143