actix_web_httpauth/extractors/
bearer.rs

1//! Extractor for the "Bearer" HTTP Authentication Scheme.
2
3use std::{borrow::Cow, default::Default};
4
5use actix_utils::future::{ready, Ready};
6use actix_web::{dev::Payload, http::header::Header, FromRequest, HttpRequest};
7
8use super::{config::AuthExtractorConfig, errors::AuthenticationError};
9pub use crate::headers::www_authenticate::bearer::Error;
10use crate::headers::{authorization, www_authenticate::bearer};
11
12/// [`BearerAuth`] extractor configuration.
13#[derive(Debug, Clone, Default)]
14pub struct Config(bearer::Bearer);
15
16impl Config {
17    /// Set challenge `scope` attribute.
18    ///
19    /// The `"scope"` attribute is a space-delimited list of case-sensitive
20    /// scope values indicating the required scope of the access token for
21    /// accessing the requested resource.
22    pub fn scope<T: Into<Cow<'static, str>>>(mut self, value: T) -> Config {
23        self.0.scope = Some(value.into());
24        self
25    }
26
27    /// Set challenge `realm` attribute.
28    ///
29    /// The "realm" attribute indicates the scope of protection in the manner
30    /// described in HTTP/1.1 [RFC 2617](https://tools.ietf.org/html/rfc2617#section-1.2).
31    pub fn realm<T: Into<Cow<'static, str>>>(mut self, value: T) -> Config {
32        self.0.realm = Some(value.into());
33        self
34    }
35}
36
37impl AsRef<bearer::Bearer> for Config {
38    fn as_ref(&self) -> &bearer::Bearer {
39        &self.0
40    }
41}
42
43impl AuthExtractorConfig for Config {
44    type Inner = bearer::Bearer;
45
46    fn into_inner(self) -> Self::Inner {
47        self.0
48    }
49}
50
51/// Extractor for HTTP Bearer auth
52///
53/// # Examples
54/// ```
55/// use actix_web_httpauth::extractors::bearer::BearerAuth;
56///
57/// async fn index(auth: BearerAuth) -> String {
58///     format!("Hello, user with token {}!", auth.token())
59/// }
60/// ```
61///
62/// If authentication fails, this extractor fetches the [`Config`] instance
63/// from the [app data] in order to properly form the `WWW-Authenticate`
64/// response header.
65///
66/// # Examples
67/// ```
68/// use actix_web::{web, App};
69/// use actix_web_httpauth::extractors::bearer::{self, BearerAuth};
70///
71/// async fn index(auth: BearerAuth) -> String {
72///     format!("Hello, {}!", auth.token())
73/// }
74///
75/// App::new()
76///     .app_data(
77///         bearer::Config::default()
78///             .realm("Restricted area")
79///             .scope("email photo"),
80///     )
81///     .service(web::resource("/index.html").route(web::get().to(index)));
82/// ```
83#[derive(Debug, Clone)]
84pub struct BearerAuth(authorization::Bearer);
85
86impl BearerAuth {
87    /// Returns bearer token provided by client.
88    pub fn token(&self) -> &str {
89        self.0.token()
90    }
91}
92
93impl FromRequest for BearerAuth {
94    type Future = Ready<Result<Self, Self::Error>>;
95    type Error = AuthenticationError<bearer::Bearer>;
96
97    fn from_request(req: &HttpRequest, _payload: &mut Payload) -> <Self as FromRequest>::Future {
98        ready(
99            authorization::Authorization::<authorization::Bearer>::parse(req)
100                .map(|auth| BearerAuth(auth.into_scheme()))
101                .map_err(|_| {
102                    let bearer = req
103                        .app_data::<Config>()
104                        .map(|config| config.0.clone())
105                        .unwrap_or_default();
106
107                    AuthenticationError::new(bearer)
108                }),
109        )
110    }
111}
112
113/// Extended error customization for HTTP `Bearer` auth.
114impl AuthenticationError<bearer::Bearer> {
115    /// Attach `Error` to the current Authentication error.
116    ///
117    /// Error status code will be changed to the one provided by the `kind`
118    /// Error.
119    pub fn with_error(mut self, kind: Error) -> Self {
120        *self.status_code_mut() = kind.status_code();
121        self.challenge_mut().error = Some(kind);
122        self
123    }
124
125    /// Attach error description to the current Authentication error.
126    pub fn with_error_description<T>(mut self, desc: T) -> Self
127    where
128        T: Into<Cow<'static, str>>,
129    {
130        self.challenge_mut().error_description = Some(desc.into());
131        self
132    }
133
134    /// Attach error URI to the current Authentication error.
135    ///
136    /// It is up to implementor to provide properly formed absolute URI.
137    pub fn with_error_uri<T>(mut self, uri: T) -> Self
138    where
139        T: Into<Cow<'static, str>>,
140    {
141        self.challenge_mut().error_uri = Some(uri.into());
142        self
143    }
144}