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}