tower_reqwest/
auth.rs

1//! Middleware for adding [`Authorization`] header to requests.
2//!
3//! This module borrows heavily from the `auth` module in the `tower-http` crate.
4//!
5//! # Example
6//!
7//! Authorizing requests using a "bearer" token.
8//!
9//! ```
10#![doc = include_str!("../examples/add_authorization.rs")]
11//! ```
12//!
13//! [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
14
15use std::task::{Context, Poll};
16
17use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
18use http::header::{HeaderValue, InvalidHeaderValue};
19use tower_layer::Layer;
20use tower_service::Service;
21
22/// Layer which adds authorization to all requests using the [`Authorization`] header.
23///
24/// # Example
25///
26/// Authorizing requests using a "bearer" token.
27///
28/// ```
29#[doc = include_str!("../examples/add_authorization.rs")]
30/// ```
31/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
32#[derive(Debug, Clone)]
33pub struct AddAuthorizationLayer {
34    value: HeaderValue,
35}
36
37/// Middleware that adds authorization all requests using the [`Authorization`] header.
38///
39/// [`Authorization`]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
40#[derive(Debug, Clone)]
41pub struct AddAuthorizationService<S> {
42    inner: S,
43    value: HeaderValue,
44}
45
46impl AddAuthorizationLayer {
47    /// Authorize requests using a username and password pair.
48    ///
49    /// The `Authorization` header will be set to `Basic {credentials}` where `credentials` is
50    /// `base64_encode("{username}:{password}")`.
51    ///
52    /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
53    /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
54    pub fn basic(
55        username: impl AsRef<str>,
56        password: impl AsRef<str>,
57    ) -> Result<Self, InvalidHeaderValue> {
58        let encoded = BASE64.encode([username.as_ref(), ":", password.as_ref()].concat());
59        Ok(Self {
60            value: ["Basic ", encoded.as_ref()].concat().parse()?,
61        })
62    }
63
64    /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
65    ///
66    /// The `Authorization` header will be set to `Bearer {token}`.
67    pub fn bearer(token: impl AsRef<str>) -> Result<Self, InvalidHeaderValue> {
68        Ok(Self {
69            value: ["Bearer ", token.as_ref()].concat().parse()?,
70        })
71    }
72
73    /// Mark the header as [sensitive].
74    ///
75    /// This can for example be used to hide the header value from logs.
76    ///
77    /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
78    #[must_use]
79    pub fn set_sensitive(mut self, sensitive: bool) -> Self {
80        self.value.set_sensitive(sensitive);
81        self
82    }
83}
84
85impl<S> Layer<S> for AddAuthorizationLayer {
86    type Service = AddAuthorizationService<S>;
87
88    fn layer(&self, inner: S) -> Self::Service {
89        AddAuthorizationService {
90            inner,
91            value: self.value.clone(),
92        }
93    }
94}
95
96impl<S> AddAuthorizationService<S> {
97    /// Authorize requests using a username and password pair.
98    ///
99    /// The `Authorization` header will be set to `Basic {credentials}` where `credentials` is
100    /// `base64_encode("{username}:{password}")`.
101    ///
102    /// Since the username and password is sent in clear text it is recommended to use HTTPS/TLS
103    /// with this method. However use of HTTPS/TLS is not enforced by this middleware.
104    pub fn basic(
105        inner: S,
106        username: impl AsRef<str>,
107        password: impl AsRef<str>,
108    ) -> Result<Self, InvalidHeaderValue> {
109        AddAuthorizationLayer::basic(username, password).map(|layer| layer.layer(inner))
110    }
111
112    /// Authorize requests using a "bearer token". Commonly used for OAuth 2.
113    ///
114    /// The `Authorization` header will be set to `Bearer {token}`.
115    pub fn bearer(inner: S, token: impl AsRef<str>) -> Result<Self, InvalidHeaderValue> {
116        AddAuthorizationLayer::bearer(token).map(|layer| layer.layer(inner))
117    }
118
119    /// Mark the header as [sensitive].
120    ///
121    /// This can for example be used to hide the header value from logs.
122    ///
123    /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
124    #[must_use]
125    pub fn set_sensitive(mut self, sensitive: bool) -> Self {
126        self.value.set_sensitive(sensitive);
127        self
128    }
129}
130
131impl<S> Service<reqwest::Request> for AddAuthorizationService<S>
132where
133    S: Service<reqwest::Request, Response = reqwest::Response>,
134{
135    type Response = S::Response;
136    type Error = S::Error;
137    type Future = S::Future;
138
139    #[inline]
140    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
141        self.inner.poll_ready(cx)
142    }
143
144    fn call(&mut self, mut req: reqwest::Request) -> Self::Future {
145        req.headers_mut()
146            .insert(http::header::AUTHORIZATION, self.value.clone());
147        self.inner.call(req)
148    }
149}