Skip to main content

better_auth_core/config/
advanced.rs

1use super::*;
2#[derive(Debug, Clone, PartialEq, Eq)]
3pub enum SameSite {
4    Strict,
5    Lax,
6    None,
7}
8
9impl std::fmt::Display for SameSite {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        match self {
12            Self::Strict => f.write_str("Strict"),
13            Self::Lax => f.write_str("Lax"),
14            Self::None => f.write_str("None"),
15        }
16    }
17}
18
19// ── Advanced configuration ──────────────────────────────────────────────
20
21/// Advanced configuration options (mirrors TS `advanced` block).
22#[derive(Debug, Clone, Default)]
23pub struct AdvancedConfig {
24    /// Trust forwarded host/protocol for URL resolution. Enable only behind a
25    /// proxy that replaces client-supplied forwarding headers. Defaults to false.
26    pub trust_forwarded_host: bool,
27
28    /// IP address extraction configuration.
29    pub ip_address: IpAddressConfig,
30
31    /// Explicit CSRF override. `None` preserves the pinned compatibility behavior
32    /// where disabling all origin checks also disables first-login CSRF checks.
33    pub disable_csrf_check: Option<bool>,
34
35    /// If `true`, callback / redirect target origin validation is skipped.
36    ///
37    /// This mirrors Better Auth TS `advanced.disableOriginCheck`.
38    /// Request-origin validation is also skipped. First-login Fetch Metadata
39    /// checks remain enabled when `disable_csrf_check` is explicitly `Some(false)`.
40    pub disable_origin_check: bool,
41
42    /// Skip origin validation for a literal path and its descendants. This does
43    /// not disable first-login cross-site navigation protection.
44    pub disable_origin_check_paths: Vec<String>,
45
46    /// Admit trailing slashes while resolving the original registered endpoint.
47    pub skip_trailing_slashes: bool,
48
49    /// Select the secure cookie name prefix and initial Secure attribute.
50    /// None uses the configured base URL protocol. Attribute overrides do not
51    /// change this choice; the serializer enforces Secure for reserved prefixes.
52    pub use_secure_cookies: Option<bool>,
53
54    /// Cross-subdomain cookie sharing configuration.
55    pub cross_sub_domain_cookies: Option<CrossSubDomainConfig>,
56
57    /// Per-cookie-name overrides (name, attributes, prefix).
58    ///
59    /// Keys are the *logical* cookie names (e.g. `"session_token"`,
60    /// `"csrf_token"`). Values specify the attributes to override.
61    pub cookies: HashMap<String, CookieOverride>,
62
63    /// Default cookie attributes applied to *every* cookie the library sets
64    /// (individual overrides in `cookies` take precedence).
65    pub default_cookie_attributes: CookieAttributes,
66
67    /// Optional prefix prepended to every cookie name (e.g. `"myapp"` →
68    /// `"myapp.session_token"`).
69    pub cookie_prefix: Option<String>,
70
71    /// Database-related advanced options.
72    pub database: AdvancedDatabaseConfig,
73
74    /// List of header names the framework trusts for extracting the
75    /// client's real IP when behind a proxy (e.g. `X-Forwarded-For`).
76    pub trusted_proxy_headers: Vec<String>,
77}
78
79/// IP-address extraction configuration.
80#[derive(Debug, Clone)]
81pub struct IpAddressConfig {
82    /// Ordered list of headers to check for the client IP.
83    /// Defaults to `["x-forwarded-for"]`. Header names are case insensitive.
84    pub headers: Vec<String>,
85
86    /// IP addresses or CIDRs removed from the right of a forwarded chain.
87    /// Invalid entries are ignored. Without valid entries, only a single
88    /// address is admitted. Deployments must prevent clients bypassing the
89    /// proxy and supplying their own trusted forwarding headers.
90    pub trusted_proxies: Vec<String>,
91
92    /// IPv6 grouping prefix; defaults to 64. Fractional values are floored,
93    /// negative values become zero, and values at least 128 or NaN preserve
94    /// the full address. IPv4-mapped addresses use IPv4 grouping.
95    pub ipv6_subnet: f64,
96
97    /// Fall back to localhost when no configured header resolves an address.
98    /// Defaults to true for NODE_ENV dev/development/test or a truthy TEST
99    /// environment flag. Applications may configure this explicitly.
100    pub localhost_fallback: bool,
101
102    /// If `true`, IP tracking is entirely disabled (no IP stored in sessions).
103    pub disable_ip_tracking: bool,
104}
105
106/// Configuration for sharing cookies across sub-domains.
107#[derive(Debug, Clone, Default)]
108pub struct CrossSubDomainConfig {
109    /// Explicit cookie domain (e.g. `".example.com"`). An empty value infers
110    /// the hostname of the configured or request-resolved base URL, without a port.
111    pub domain: String,
112}
113
114/// Overridable cookie attributes.
115#[derive(Debug, Clone, Default)]
116pub struct CookieAttributes {
117    /// Override `Secure` flag.
118    pub secure: Option<bool>,
119    /// Override `HttpOnly` flag.
120    pub http_only: Option<bool>,
121    /// Override `SameSite` policy.
122    pub same_site: Option<SameSite>,
123    /// Override `Path`.
124    pub path: Option<String>,
125    /// Override `Max-Age` (seconds).
126    pub max_age: Option<f64>,
127    /// Explicit expiry, checked at emission against the published 400-day limit.
128    pub expires: Option<chrono::DateTime<chrono::Utc>>,
129    /// Emit the published `Partitioned` attribute after SameSite.
130    pub partitioned: Option<bool>,
131    /// Override cookie `Domain`.
132    pub domain: Option<String>,
133}
134
135/// Per-cookie override entry.
136#[derive(Debug, Clone, Default)]
137pub struct CookieOverride {
138    /// Custom name to use instead of the logical name.
139    pub name: Option<String>,
140    /// Attribute overrides for this cookie.
141    pub attributes: CookieAttributes,
142}
143
144/// Database-related advanced options.
145#[derive(Debug, Clone)]
146pub struct AdvancedDatabaseConfig {
147    /// Default `LIMIT` for "find many" queries.
148    pub default_find_many_limit: usize,
149
150    /// Declares that the database uses numeric IDs, as upstream's
151    /// `useNumberId`. IDs are always generated as strings; this only makes
152    /// invitation email verification required by default, because numeric
153    /// invitation IDs are guessable.
154    pub use_number_id: bool,
155}
156
157impl Default for IpAddressConfig {
158    fn default() -> Self {
159        Self {
160            headers: vec!["x-forwarded-for".to_owned()],
161            trusted_proxies: Vec::new(),
162            ipv6_subnet: 64.0,
163            localhost_fallback: matches!(
164                std::env::var("NODE_ENV").as_deref(),
165                Ok("dev" | "development" | "test")
166            ) || std::env::var("TEST")
167                .is_ok_and(|value| !matches!(value.as_str(), "" | "false")),
168            disable_ip_tracking: false,
169        }
170    }
171}
172
173impl Default for AdvancedDatabaseConfig {
174    fn default() -> Self {
175        Self {
176            default_find_many_limit: 100,
177            use_number_id: false,
178        }
179    }
180}