| Crates.io | firebase-admin-sdk |
| lib.rs | firebase-admin-sdk |
| version | 0.2.0 |
| created_at | 2026-01-17 16:18:25.524965+00 |
| updated_at | 2026-01-19 13:57:49.750385+00 |
| description | Firebase Admin SDK for Rust, enabling interaction with Firebase services (Auth, FCM, Firestore, Storage, etc.) from a Rust backend. |
| homepage | |
| repository | https://github.com/shovelmn12/firebase-admin-sdk-rs |
| max_upload_size | |
| id | 2050733 |
| size | 354,256 |
A Rust implementation of the Firebase Admin SDK. This library allows you to interact with Firebase services such as Authentication, Cloud Messaging (FCM), Remote Config, and Firestore from your Rust backend.
listen() API.Add this to your Cargo.toml:
[dependencies]
firebase-admin-sdk = "0.1.0" # Replace with actual version
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
futures = "0.3" # Required for Firestore Listen API streams
The entry point for the SDK is the FirebaseApp struct. You will need a service account JSON file from the Firebase Console.
use firebase_admin_sdk::{FirebaseApp, yup_oauth2};
#[tokio::main]
async fn main() {
// Load the service account key (e.g., from a file)
let service_account_key = yup_oauth2::read_service_account_key("service-account.json").await.unwrap();
let app = FirebaseApp::new(service_account_key);
// Access services
let auth = app.auth();
let messaging = app.messaging();
let remote_config = app.remote_config();
let firestore = app.firestore();
}
use firebase_admin_sdk::auth::models::CreateUserRequest;
async fn create_user(app: &firebase_admin_sdk::FirebaseApp) {
let auth = app.auth();
let request = CreateUserRequest {
uid: Some("test-uid".to_string()),
email: Some("test@example.com".to_string()),
..Default::default()
};
match auth.create_user(request).await {
Ok(user) => println!("Created user: {:?}", user.uid),
Err(e) => eprintln!("Error: {}", e),
}
}
use firebase_admin_sdk::messaging::models::{Message, Notification};
async fn send_message(app: &firebase_admin_sdk::FirebaseApp) {
let messaging = app.messaging();
let message = Message {
token: Some("device_token".to_string()),
notification: Some(Notification {
title: Some("Hello".to_string()),
body: Some("World".to_string()),
..Default::default()
}),
..Default::default()
};
match messaging.send(&message).await {
Ok(id) => println!("Sent message: {}", id),
Err(e) => eprintln!("Error: {}", e),
}
}
async fn get_config(app: &firebase_admin_sdk::FirebaseApp) {
let rc = app.remote_config();
match rc.get().await {
Ok(config) => println!("Current config: {:?}", config),
Err(e) => eprintln!("Error: {}", e),
}
}
use serde_json::json;
async fn add_document(app: &firebase_admin_sdk::FirebaseApp) {
let firestore = app.firestore();
let doc_ref = firestore.collection("users").doc("user1");
let data = json!({
"name": "John Doe",
"age": 30
});
match doc_ref.set(&data).await {
Ok(_) => println!("Document saved"),
Err(e) => eprintln!("Error: {}", e),
}
}
You can listen for real-time updates on a document or an entire collection using the listen() method.
use futures::stream::StreamExt;
async fn listen_to_document(app: &firebase_admin_sdk::FirebaseApp) {
let firestore = app.firestore();
let doc_ref = firestore.collection("users").doc("user1");
let mut stream = doc_ref.listen().await.expect("Failed to create stream");
while let Some(response_result) = stream.next().await {
match response_result {
Ok(response) => {
if let Some(change) = response.document_change {
println!("Document changed: {:?}", change.document);
}
}
Err(e) => eprintln!("Stream error: {}", e),
}
}
}
async fn upload_file(app: &firebase_admin_sdk::FirebaseApp) {
let storage = app.storage();
let bucket = storage.bucket(None); // Uses default bucket
let file_content = b"Hello, World!";
let file = bucket.file("hello.txt");
match file.save(file_content, "text/plain").await {
Ok(_) => println!("File uploaded"),
Err(e) => eprintln!("Error: {}", e),
}
// Generate a V4 signed URL
let options = firebase_admin_sdk::storage::GetSignedUrlOptions {
method: firebase_admin_sdk::storage::SignedUrlMethod::GET,
expires: std::time::SystemTime::now() + std::time::Duration::from_secs(3600), // 1 hour
content_type: None,
};
match file.get_signed_url(options) {
Ok(url) => println!("Signed URL: {}", url),
Err(e) => eprintln!("Error generating signed URL: {}", e),
}
}
async fn delete_reports(app: &firebase_admin_sdk::FirebaseApp) {
let crashlytics = app.crashlytics();
match crashlytics.delete_crash_reports("1:1234567890:android:321abc456def7890", "user_uid").await {
Ok(_) => println!("Crash reports deleted"),
Err(e) => eprintln!("Error: {}", e),
}
}
This SDK is designed with specific architectural patterns to ensure usability, performance, and reliability.
One of the key design goals was to keep the FirebaseApp::new() constructor synchronous. In Rust, async constructors are not idiomatic and can complicate application startup logic.
However, Firebase APIs require OAuth2 authentication, which involves asynchronous HTTP requests to fetch tokens. To bridge this gap, we use a lazy initialization pattern:
FirebaseApp::new() simply stores the ServiceAccountKey and returns immediately.AuthMiddleware.tokio::sync::OnceCell that holds the authenticator.auth.get_user(...)), the middleware checks the OnceCell. If it's empty, it asynchronously initializes the OAuth2 authenticator and fetches a token.The SDK leverages reqwest_middleware to build a robust HTTP client stack:
Authorization header.This separation of concerns keeps the business logic in the service modules (Auth, Messaging, etc.) clean and focused on the Firebase APIs themselves.
FirebaseApp acts as a lightweight factory and configuration holder.
app.auth() or app.messaging() creates a new, lightweight client instance.ServiceAccountKey (cloned cheaply) but are otherwise independent.Where possible, the SDK uses strong typing to prevent runtime errors:
Message struct uses generic builders or strictly typed fields to ensure valid payloads.ETag is handled automatically to ensure safe concurrent updates (If-Match headers).DocumentReference and CollectionReference types mirror the path structure of your database.