actix_firebase_auth/
impls.rs1use actix_web::error::InternalError;
2use actix_web::http::{header, StatusCode};
3use actix_web::{dev, http::header::Header, web, FromRequest, HttpRequest};
4use actix_web::{HttpResponse, ResponseError};
5use actix_web_httpauth::headers::authorization::{Authorization, Bearer};
6use futures::future::{err, ok, Ready};
7
8use crate::jwk::{PublicKeysError, VerificationError};
9use crate::{Error, FirebaseAuth, FirebaseUser};
10
11fn status_code_from_http_err(err: &reqwest::Error) -> StatusCode {
12 let code = err.status().map_or_else(|| 500, |s| s.as_u16());
13 StatusCode::from_u16(code).unwrap_or(StatusCode::BAD_GATEWAY) }
15
16impl ResponseError for Error {
17 fn error_response(&self) -> HttpResponse {
18 HttpResponse::build(self.status_code()).json(self.to_string())
19 }
20
21 fn status_code(&self) -> StatusCode {
22 match self {
23 Error::PublicKeysError(err) => match err {
24 PublicKeysError::FetchPublicKeys(http_err)
25 | PublicKeysError::PublicKeyParseError(http_err) => {
26 status_code_from_http_err(http_err)
27 }
28
29 PublicKeysError::MissingCacheControlHeader
30 | PublicKeysError::MissingMaxAgeDirective
31 | PublicKeysError::EmptyMaxAgeDirective
32 | PublicKeysError::InvalidMaxAgeValue => {
33 StatusCode::INTERNAL_SERVER_ERROR
35 }
36 },
37
38 Error::VerificationError(err) => match err {
39 VerificationError::InvalidSignature => {
40 StatusCode::UNAUTHORIZED
42 }
43 VerificationError::InvalidKeyAlgorithm => {
44 StatusCode::BAD_REQUEST
46 }
47 VerificationError::InvalidToken => {
48 StatusCode::BAD_REQUEST
50 }
51 VerificationError::NoKidHeader => {
52 StatusCode::BAD_REQUEST
54 }
55 VerificationError::NoMatchingKid => {
56 StatusCode::UNAUTHORIZED
58 }
59 VerificationError::CannotDecodePublicKeys => {
60 StatusCode::INTERNAL_SERVER_ERROR
62 }
63 VerificationError::CannotDecodeJwt(_) => {
64 StatusCode::UNAUTHORIZED
66 }
67 },
68
69 #[cfg(feature = "idp")]
70 Error::IdpError(err) => err.error_response().status(),
71 }
72 }
73}
74
75impl FromRequest for FirebaseUser {
76 type Error = actix_web::Error;
77 type Future = Ready<Result<Self, Self::Error>>;
78
79 fn from_request(req: &HttpRequest, _: &mut dev::Payload) -> Self::Future {
80 let firebase_auth = req
81 .app_data::<web::Data<FirebaseAuth>>()
82 .expect("FirebaseAuth should be initialized in application data");
83
84 let bearer = match Authorization::<Bearer>::parse(req) {
85 Ok(header) => header.into_scheme(),
86 Err(_) => {
87 return err(missing_or_malformed_auth_header());
94 }
95 };
96
97 let id_token = bearer.token();
98
99 match firebase_auth.verify(id_token) {
100 Ok(user) => ok(user),
101 Err(crate::Error::VerificationError(
102 VerificationError::CannotDecodePublicKeys,
103 )) => err(internal_token_verification_error()),
104 Err(other) => err(invalid_token_error(&other)),
105 }
106 }
107}
108
109fn internal_token_verification_error() -> actix_web::Error {
110 let response = HttpResponse::InternalServerError()
111 .body("Internal error during token verification");
112
113 InternalError::from_response("token_verification_failure", response).into()
114}
115
116fn missing_or_malformed_auth_header() -> actix_web::Error {
117 unauthorized_with_www_authenticate(
118 "invalid_request",
119 "Authorization header missing or not using Bearer scheme",
120 "Authorization header is missing or malformed",
121 )
122}
123
124fn invalid_token_error(err: &crate::Error) -> actix_web::Error {
125 unauthorized_with_www_authenticate(
126 "invalid_token",
127 &err.to_string(),
128 format!("Failed to verify Firebase ID token: {err}"),
129 )
130}
131
132fn unauthorized_with_www_authenticate(
134 www_error_code: &str,
135 www_error_description: &str,
136 body: impl Into<String>,
137) -> actix_web::Error {
138 let header_value = format!(
139 r#"Bearer realm="firebase", error="{www_error_code}", error_description="{www_error_description}""#
140 );
141
142 let response = HttpResponse::Unauthorized()
143 .insert_header((header::WWW_AUTHENTICATE, header_value))
144 .body(body.into());
145
146 InternalError::from_response("auth_error", response).into()
147}