Skip to main content

rs_firebase_admin_sdk/
lib.rs

1pub mod api_uri;
2pub mod auth;
3pub mod client;
4pub mod credentials;
5#[cfg(feature = "tokens")]
6pub mod jwt;
7pub mod util;
8
9use auth::FirebaseAuth;
10use client::ReqwestApiClient;
11use core::marker::PhantomData;
12use credentials::{GCPCredentialsError, emulator::EmulatorCredentials, get_project_id};
13use error_stack::{Report, ResultExt};
14use google_cloud_auth::credentials::{AccessTokenCredentials, Builder};
15pub use google_cloud_auth::credentials::{Credentials, CredentialsProvider};
16
17const FIREBASE_AUTH_SCOPES: [&str; 2] = [
18    "https://www.googleapis.com/auth/cloud-platform",
19    "https://www.googleapis.com/auth/userinfo.email",
20];
21
22/// Base privileged manager for Firebase
23pub struct App<C> {
24    credentials: Credentials,
25    project_id: String,
26    _credentials_provider: PhantomData<C>,
27}
28
29impl App<EmulatorCredentials> {
30    /// Firebase app backend by emulator
31    pub fn emulated() -> Self {
32        let credentials = EmulatorCredentials::default();
33        Self {
34            project_id: credentials.project_id.clone(),
35            credentials: credentials.into(),
36            _credentials_provider: PhantomData,
37        }
38    }
39
40    /// Firebase authentication manager for emulator
41    pub fn auth(&self, emulator_url: String) -> FirebaseAuth<ReqwestApiClient> {
42        let client = ReqwestApiClient::new(reqwest::Client::new(), self.credentials.clone());
43
44        FirebaseAuth::emulated(emulator_url, &self.project_id, client)
45    }
46
47    /// OIDC token verifier for emulator
48    #[cfg(feature = "tokens")]
49    pub fn id_token_verifier(&self) -> impl jwt::TokenValidator {
50        jwt::EmulatorValidator
51    }
52}
53
54impl App<AccessTokenCredentials> {
55    /// Create instance of Firebase app for live project with an explicit project ID,
56    /// bypassing environment variable and credential header resolution.
57    pub async fn live_with_project_id(
58        project_id: &str,
59    ) -> Result<Self, Report<GCPCredentialsError>> {
60        let credentials: Credentials = Builder::default()
61            .with_scopes(FIREBASE_AUTH_SCOPES)
62            .build_access_token_credentials()
63            .change_context(GCPCredentialsError)?
64            .into();
65
66        Ok(Self {
67            credentials,
68            project_id: project_id.to_string(),
69            _credentials_provider: PhantomData,
70        })
71    }
72
73    /// Create instance of Firebase app for live project
74    pub async fn live() -> Result<Self, Report<GCPCredentialsError>> {
75        let credentials: Credentials = Builder::default()
76            .with_scopes(FIREBASE_AUTH_SCOPES)
77            .build_access_token_credentials()
78            .change_context(GCPCredentialsError)?
79            .into();
80
81        let project_id = get_project_id(&credentials)
82            .await
83            .change_context(GCPCredentialsError)?;
84
85        Ok(Self {
86            credentials,
87            project_id,
88            _credentials_provider: PhantomData,
89        })
90    }
91
92    /// Create Firebase authentication manager
93    pub fn auth(&self) -> FirebaseAuth<ReqwestApiClient> {
94        let client = ReqwestApiClient::new(reqwest::Client::new(), self.credentials.clone());
95
96        FirebaseAuth::live(&self.project_id, client)
97    }
98
99    /// Create OIDC token verifier
100    #[cfg(feature = "tokens")]
101    pub async fn id_token_verifier(
102        &self,
103    ) -> Result<impl jwt::TokenValidator, Report<credentials::GCPCredentialsError>> {
104        jwt::LiveValidator::new_jwt_validator(self.project_id.clone())
105            .change_context(credentials::GCPCredentialsError)
106    }
107
108    /// Create cookie token verifier
109    #[cfg(feature = "tokens")]
110    pub async fn cookie_token_verifier(
111        &self,
112    ) -> Result<impl jwt::TokenValidator, Report<credentials::GCPCredentialsError>> {
113        jwt::LiveValidator::new_cookie_validator(self.project_id.clone())
114            .change_context(credentials::GCPCredentialsError)
115    }
116}