1#[derive(Clone, Debug, Default)]
2pub struct AuthInterceptor {
3 auth: Option<tonic::metadata::MetadataValue<tonic::metadata::Ascii>>,
4}
5
6impl AuthInterceptor {
7 pub fn basic<U, P>(username: U, password: Option<P>) -> Self
9 where
10 U: std::fmt::Display,
11 P: std::fmt::Display,
12 {
13 use base64::prelude::BASE64_STANDARD;
14 use base64::write::EncoderWriter;
15 use std::io::Write;
16
17 let mut buf = b"Basic ".to_vec();
18 {
19 let mut encoder = EncoderWriter::new(&mut buf, &BASE64_STANDARD);
20 let _ = write!(encoder, "{username}:");
21 if let Some(password) = password {
22 let _ = write!(encoder, "{password}");
23 }
24 }
25 let mut header = tonic::metadata::MetadataValue::try_from(buf)
26 .expect("base64 is always valid HeaderValue");
27 header.set_sensitive(true);
28
29 Self { auth: Some(header) }
30 }
31
32 pub fn bearer<T>(token: T) -> Self
34 where
35 T: std::fmt::Display,
36 {
37 let header_value = format!("Bearer {token}");
38 let mut header = tonic::metadata::MetadataValue::try_from(header_value)
39 .expect("token is always valid HeaderValue");
40 header.set_sensitive(true);
41
42 Self { auth: Some(header) }
43 }
44}
45
46impl tonic::service::Interceptor for AuthInterceptor {
47 fn call(
48 &mut self,
49 mut request: tonic::Request<()>,
50 ) -> std::result::Result<tonic::Request<()>, tonic::Status> {
51 if let Some(auth) = self.auth.clone() {
52 request
53 .metadata_mut()
54 .insert(http::header::AUTHORIZATION.as_str(), auth);
55 }
56 Ok(request)
57 }
58}
59
60impl tonic::service::Interceptor for &mut AuthInterceptor {
61 fn call(
62 &mut self,
63 mut request: tonic::Request<()>,
64 ) -> std::result::Result<tonic::Request<()>, tonic::Status> {
65 if let Some(auth) = self.auth.clone() {
66 request
67 .metadata_mut()
68 .insert(http::header::AUTHORIZATION.as_str(), auth);
69 }
70 Ok(request)
71 }
72}