Skip to main content

better_auth_core/session/
response.rs

1use super::SessionManager;
2use crate::{AuthRequest, AuthResponse, AuthResult, AuthSchema};
3
4impl<S: AuthSchema> SessionManager<S> {
5    /// Finalize session cookies and Bearer response headers.
6    pub fn finish_response(
7        &self,
8        req: &AuthRequest,
9        response: &mut AuthResponse,
10    ) -> AuthResult<()> {
11        let endpoint_headers = std::mem::take(&mut response.headers);
12        response.headers = req.take_response_headers()?;
13        response.headers.merge(endpoint_headers);
14        let session_cookie = response
15            .headers
16            .get_all("set-cookie")
17            .filter_map(|value| cookie::Cookie::parse(value.as_str()).ok())
18            .filter(|cookie| {
19                cookie.name()
20                    == self
21                        .config
22                        .auth_cookie("session_token", Default::default())
23                        .name
24            })
25            .last()
26            .filter(|cookie| {
27                !cookie.value().is_empty()
28                    && cookie.max_age().is_none_or(|age| age.whole_seconds() != 0)
29            })
30            .map(|cookie| cookie.value().to_string());
31        if let Some(signed_token) = session_cookie
32            && self.config.session.bearer.is_some()
33        {
34            let signed_token = percent_encoding::percent_decode_str(&signed_token)
35                .decode_utf8()
36                .map_err(|error| {
37                    crate::AuthError::internal(format!("Decoding session cookie: {error}"))
38                })?;
39            let _ = response
40                .headers
41                .insert("set-auth-token", signed_token.into_owned());
42            let mut exposed: Vec<_> = response
43                .headers
44                .get("access-control-expose-headers")
45                .map(|header| {
46                    header
47                        .split(',')
48                        .map(str::trim)
49                        .filter(|value| !value.is_empty())
50                        .map(str::to_string)
51                        .collect()
52                })
53                .unwrap_or_default();
54            if !exposed
55                .iter()
56                .any(|name| name.eq_ignore_ascii_case("set-auth-token"))
57            {
58                exposed.push("set-auth-token".into());
59            }
60            let _ = response
61                .headers
62                .insert("access-control-expose-headers", exposed.join(", "));
63        }
64        if req.path().ends_with("/get-session") {
65            let _ = response.headers.insert("Cache-Control", "no-store");
66            let _ = response.headers.insert("Pragma", "no-cache");
67        }
68        Ok(())
69    }
70}