Skip to main content

nextcloud_auth/bearer/
bearer_auth.rs

1use std::fmt;
2
3use nextcloud_sdk_core::{AuthProvider, Headers};
4
5use super::BearerToken;
6
7/// Applies an OAuth2 access token as an `Authorization: Bearer` header.
8#[derive(Clone)]
9pub struct BearerAuth {
10    token: BearerToken,
11}
12
13impl BearerAuth {
14    /// Builds a provider from a token string.
15    pub fn new(token: impl Into<String>) -> Self {
16        Self {
17            token: BearerToken::new(token),
18        }
19    }
20
21    /// Builds a provider from an already-wrapped token.
22    pub const fn from_token(token: BearerToken) -> Self {
23        Self { token }
24    }
25
26    /// The token this provider applies.
27    pub const fn token(&self) -> &BearerToken {
28        &self.token
29    }
30
31    /// The header value sent to the server.
32    pub fn header_value(&self) -> String {
33        format!("Bearer {}", self.token.expose())
34    }
35}
36
37impl AuthProvider for BearerAuth {
38    fn authenticate(&self, headers: &mut Headers) {
39        tracing::trace!("Applying Bearer token authentication header");
40        headers.set("Authorization", self.header_value());
41    }
42}
43
44impl fmt::Debug for BearerAuth {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.debug_struct("BearerAuth")
47            .field("token", &self.token)
48            .finish()
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use nextcloud_sdk_core::{AuthProvider, Header, Headers};
55
56    use super::BearerAuth;
57
58    fn bearer() -> BearerAuth {
59        BearerAuth::new("access-token")
60    }
61
62    #[test]
63    fn header_value_prefixes_the_token_with_bearer() {
64        assert_eq!(bearer().header_value(), "Bearer access-token");
65    }
66
67    #[test]
68    fn authenticate_sets_the_authorization_header() {
69        let mut headers = Headers::new();
70        bearer().authenticate(&mut headers);
71        assert_eq!(headers.get("Authorization"), Some("Bearer access-token"));
72    }
73
74    #[test]
75    fn authenticate_replaces_an_existing_authorization_header() {
76        let mut headers = Headers::new().with(Header::new("Authorization", "Basic c3RhbGU="));
77        bearer().authenticate(&mut headers);
78        assert_eq!(headers.len(), 1);
79        assert_eq!(headers.get("Authorization"), Some("Bearer access-token"));
80    }
81
82    #[test]
83    fn debug_redacts_the_token() {
84        let rendered = format!("{:?}", bearer());
85        assert!(!rendered.contains("access-token"));
86        assert!(rendered.contains("<redacted>"));
87    }
88}