Skip to content

firebase/firebase-admin-dart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

171 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Firebase Admin Dart SDK

Table of Contents

Overview

Firebase provides the tools and infrastructure you need to develop your app, grow your user base, and earn money. The Firebase Admin Dart SDK enables access to Firebase services from privileged environments (such as servers or cloud) in Dart.

For more information, visit the Firebase Admin SDK setup guide.

Installation

The Firebase Admin Dart SDK is available on pub.dev as dart_firebase_admin:

$ dart pub add dart_firebase_admin

To use the SDK in your application, import it from any Dart file:

import 'package:dart_firebase_admin/dart_firebase_admin.dart';

Add the Firebase Admin SDK to your server

Prerequisites

Make sure that you have a server app.

Make sure that your server runs Dart SDK 3.9 or higher.

Set up a Firebase project and service account

To use the Firebase Admin SDK, you'll need the following:

  • A Firebase project.
  • A Firebase Admin SDK service account to communicate with Firebase. This service account is created automatically when you create a Firebase project or add Firebase to a Google Cloud project.
  • A configuration file with your service account's credentials.

If you don't already have a Firebase project, you need to create one in the Firebase console. Visit Understand Firebase Projects to learn more about Firebase projects.

Add the SDK

If you are setting up a new project, you need to install the SDK for the language of your choice.

The Firebase Admin Dart SDK is available on pub.dev as dart_firebase_admin:

$ dart pub add dart_firebase_admin

To use the module in your application, import it from any Dart file:

import 'package:dart_firebase_admin/dart_firebase_admin.dart';

Initialize the SDK

Once you have created a Firebase project, you can initialize the SDK with Google Application Default Credentials. Because default credentials lookup is fully automated in Google environments, with no need to supply environment variables or other configuration, this way of initializing the SDK is strongly recommended for applications running in Google environments such as Firebase App Hosting, Cloud Run, App Engine, and Cloud Functions for Firebase.

final app = FirebaseApp.initializeApp();

To optionally specify initialization options for services such as Realtime Database, Cloud Storage, or Cloud Functions, use the FIREBASE_CONFIG environment variable. If the content of the FIREBASE_CONFIG variable begins with a { it will be parsed as a JSON object. Otherwise the SDK assumes that the string is the path of a JSON file containing the options.

Note: The FIREBASE_CONFIG environment variable is included automatically in App Hosting backends and Cloud Functions for Firebase functions.

export FIREBASE_CONFIG='{"projectId":"my-project"}'
// Options are read automatically from FIREBASE_CONFIG
final app = FirebaseApp.initializeApp();

Initialize the SDK in non-Google environments

If you are working in a non-Google server environment in which default credentials lookup can't be fully automated, you can initialize the SDK with an exported service account key file.

Important: Extremely high security awareness is required when working with service account keys, as they are vulnerable to certain types of threats. See Best practices for managing service account keys.

Firebase projects support Google service accounts, which you can use to call Firebase server APIs from your app server or trusted environment. If you're developing code locally or deploying your application on-premises, you can use credentials obtained via this service account to authorize server requests.

To generate a private key file for your service account:

  1. In the Firebase console, open Settings > Service Accounts.
  2. Click Generate New Private Key, then confirm by clicking Generate Key.
  3. Securely store the JSON file containing the key.

When authorizing via a service account, you have two choices for providing the credentials to your application. You can either set the GOOGLE_APPLICATION_CREDENTIALS environment variable, or you can explicitly pass the path to the service account key in code. The first option is more secure and is strongly recommended.

To set the environment variable:

Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

After you've completed the above steps, Application Default Credentials (ADC) is able to implicitly determine your credentials, allowing you to use service account credentials when testing or running in non-Google environments.

The initializeApp method allows for creating multiple named app instances and specifying a custom credential, project ID and other options:

final app = FirebaseApp.initializeApp(
  options: AppOptions(
    credential: Credential.fromServiceAccount(File("path/to/credential.json")),
    projectId: "custom-project-id",
  ),
  name: "CUSTOM_APP",
);

The following Credential constructors are available:

  • Credential.fromApplicationDefaultCredentials({String? serviceAccountId}) β€” Uses Application Default Credentials (recommended for Google environments). Optionally accepts a serviceAccountId to override the service account email.
  • Credential.fromServiceAccount(File) β€” Loads credentials from a service account JSON file downloaded from the Firebase Console.
  • Credential.fromServiceAccountParams({required String privateKey, required String email, required String projectId, String? clientId}) β€” Builds credentials from individual service account fields directly.

Using Workload Identity Federation

Workload Identity Federation lets external workloads (such as GitHub Actions, AWS, or Azure) authenticate as a Google service account without a long-lived key file.

Once your WIF credential configuration file is generated, point GOOGLE_APPLICATION_CREDENTIALS to it:

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/wif-credential-config.json"

Then initialize the SDK with ADC, providing the impersonated service account email via serviceAccountId. This is required because WIF credential configs do not embed a client_email field, unlike service account key files:

final app = FirebaseApp.initializeApp(
  options: AppOptions(
    credential: Credential.fromApplicationDefaultCredentials(
      serviceAccountId: 'my-service-account@my-project.iam.gserviceaccount.com',
    ),
    projectId: 'my-project',
  ),
);

Initialize multiple apps

In most cases, you only have to initialize a single default app:

// Initialize the default app
final defaultApp = FirebaseApp.initializeApp();

print(defaultApp.name); // '[DEFAULT]'

// Access services from the default app
final defaultAuth = defaultApp.auth();
final defaultFirestore = defaultApp.firestore();

Some use cases require you to create multiple apps at the same time. For example, you might want to read data from the Realtime Database of one Firebase project and mint custom tokens for another project. Or you might want to authenticate two apps with separate credentials. The Firebase SDK allows you create multiple apps at the same time, each with their own configuration information.

// Each AppOptions points to a different Firebase project
final defaultApp = FirebaseApp.initializeApp(
  options: AppOptions(
    credential: Credential.fromServiceAccount(File('path/to/default-service-account.json')),
    projectId: 'my-default-project',
  ),
);

// Initialize another app with a different config
final otherApp = FirebaseApp.initializeApp(
  options: AppOptions(
    credential: Credential.fromServiceAccount(File('path/to/other-service-account.json')),
    projectId: 'my-other-project',
  ),
  name: 'other',
);

print(defaultApp.name); // '[DEFAULT]'
print(otherApp.name);   // 'other'

// Access services from each app
final defaultAuth = defaultApp.auth();
final defaultFirestore = defaultApp.firestore();

final otherAuth = otherApp.auth();
final otherFirestore = otherApp.firestore();

Note: Each app instance has its own configuration options and authentication state.

Testing with gcloud end user credentials

When testing the Admin SDK locally with Google Application Default Credentials obtained by running gcloud auth application-default login, additional changes are needed to use Firebase Authentication due to the following:

  • Firebase Authentication does not accept gcloud end user credentials generated using the gcloud OAuth client ID.
  • Firebase Authentication requires the project ID to be provided on initialization for these type of end user credentials.

You can specify the project ID explicitly on app initialization or just use the GOOGLE_CLOUD_PROJECT environment variable. The latter avoids the need to make any additional changes to test your code.

To explicitly specify the project ID:

final app = FirebaseApp.initializeApp(
  options: AppOptions(
    credential: Credential.fromApplicationDefaultCredentials(),
    projectId: '<FIREBASE_PROJECT_ID>',
  ),
);

Alternatively, set the GOOGLE_CLOUD_PROJECT environment variable to avoid changing your code:

export GOOGLE_CLOUD_PROJECT="<FIREBASE_PROJECT_ID>"

Usage

Once you have initialized an app instance with a credential, you can use any of the supported services to interact with Firebase.

Authentication

import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/auth.dart';

final app = FirebaseApp.initializeApp();
final auth = app.auth();

getUser / getUserByEmail

// Get user by UID
final userById = await auth.getUser('<user-id>');
print(userById.displayName);

// Get user by email
final userByEmail = await auth.getUserByEmail('user@example.com');
print(userByEmail.displayName);

createUser

final user = await auth.createUser(
  CreateRequest(
    email: 'user@example.com',
    password: 'password123',
    displayName: 'John Doe',
  ),
);
print(user.uid);

updateUser

final updatedUser = await auth.updateUser(
  '<user-id>',
  UpdateRequest(
    displayName: 'Jane Doe',
    disabled: false,
  ),
);
print(updatedUser.displayName);

deleteUser / listUsers

// Delete a user
await auth.deleteUser('<user-id>');

// List users (max 1000 per page)
final result = await auth.listUsers(maxResults: 100);
final users = result.users;
final nextPageToken = result.pageToken;

verifyIdToken

// Verify an ID token from a client application (e.g. from request headers)
final idToken = req.headers['Authorization'].split(' ')[1];
final decodedToken = await auth.verifyIdToken(idToken, checkRevoked: true);
print(decodedToken.uid);

createCustomToken

final customToken = await auth.createCustomToken(
  '<user-id>',
  developerClaims: {'role': 'admin'},
);

setCustomUserClaims

await auth.setCustomUserClaims('<user-id>', customUserClaims: {'role': 'admin'});

App Check

import 'package:dart_firebase_admin/dart_firebase_admin.dart';

final app = FirebaseApp.initializeApp();

verifyToken

final response = await app.appCheck().verifyToken('<app-check-token>');
print('App ID: ${response.appId}');

createToken

final result = await app.appCheck().createToken('<app-id>');
print('Token: ${result.token}');

Firestore

import 'dart:async';
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:google_cloud_firestore/google_cloud_firestore.dart';

final app = FirebaseApp.initializeApp();
final firestore = app.firestore();

set / update / delete

final ref = firestore.collection('users').doc('<user-id>');

// Set a document (creates or overwrites)
await ref.set({'name': 'John Doe', 'age': 27});

// Update specific fields
await ref.update({'age': 28});

// Delete a document
await ref.delete();

get / query

// Get a single document
final snapshot = await firestore.collection('users').doc('<user-id>').get();
print(snapshot.data());

// Query a collection
final querySnapshot = await firestore
    .collection('users')
    .where('age', WhereFilter.greaterThan, 18)
    .orderBy('age', descending: true)
    .get();
print(querySnapshot.docs);

getAll

// Fetch multiple documents at once
final snapshots = await firestore.getAll([
  firestore.collection('users').doc('user-1'),
  firestore.collection('users').doc('user-2'),
]);
for (final snap in snapshots) {
  print(snap.data());
}

batch

final batch = firestore.batch();
batch.set(firestore.collection('users').doc('user-1'), {'name': 'Alice'});
batch.update(firestore.collection('users').doc('user-2'), {FieldPath(const ['age']): 30});
batch.delete(firestore.collection('users').doc('user-3'));
await batch.commit();

bulkWriter

final bulkWriter = firestore.bulkWriter();
for (var i = 0; i < 10; i++) {
  unawaited(
    bulkWriter.set(
      firestore.collection('items').doc('item-$i'),
      {'index': i},
    ),
  );
}
await bulkWriter.close();

runTransaction

final balance = await firestore.runTransaction((tsx) async {
  final ref = firestore.collection('users').doc('<user-id>');
  final snapshot = await tsx.get(ref);
  final currentBalance = snapshot.exists ? snapshot.data()?['balance'] ?? 0 : 0;
  final newBalance = currentBalance + 10;
  tsx.update(ref, {'balance': newBalance});
  return newBalance;
});

Functions

import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/functions.dart';

final app = FirebaseApp.initializeApp();
final queue = app.functions().taskQueue('<task-name>');

enqueue

await queue.enqueue({'userId': 'user-123', 'action': 'sendWelcomeEmail'});

enqueue with TaskOptions

// Delay delivery by 1 hour
await queue.enqueue(
  {'action': 'cleanupTempFiles'},
  TaskOptions(schedule: DelayDelivery(3600)),
);

// Schedule at a specific time
await queue.enqueue(
  {'action': 'sendReport'},
  TaskOptions(schedule: AbsoluteDelivery(DateTime.now().add(Duration(hours: 1)))),
);

// Use a custom ID for deduplication
await queue.enqueue(
  {'orderId': 'order-456', 'action': 'processPayment'},
  TaskOptions(id: 'payment-order-456'),
);

enqueue with TaskOptionsExperimental

// Route the task to a custom URI (beta feature)
await queue.enqueue(
  {'action': 'customHandler'},
  TaskOptions(
    experimental: TaskOptionsExperimental(
      uri: 'https://my-service.example.com/task-handler',
    ),
  ),
);

delete

await queue.delete('payment-order-456');

Messaging

import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:dart_firebase_admin/messaging.dart';

final app = FirebaseApp.initializeApp();
final messaging = app.messaging();

send

// Send to a specific device
await messaging.send(
  TokenMessage(
    token: '<device-token>',
    notification: Notification(title: 'Hello', body: 'World!'),
    data: {'key': 'value'},
  ),
);

// Send to a topic
await messaging.send(
  TopicMessage(
    topic: '<topic-name>',
    notification: Notification(title: 'Hello', body: 'World!'),
  ),
);

// Send to a condition
await messaging.send(
  ConditionMessage(
    condition: "'stock-GOOG' in topics || 'industry-tech' in topics",
    notification: Notification(title: 'Hello', body: 'World!'),
  ),
);

sendEach

// Send up to 500 messages in a single call
final response = await messaging.sendEach([
  TopicMessage(topic: 'topic-1', notification: Notification(title: 'Message 1')),
  TopicMessage(topic: 'topic-2', notification: Notification(title: 'Message 2')),
]);
print('Sent: ${response.successCount}, Failed: ${response.failureCount}');

sendEachForMulticast

// Send one message to multiple device tokens
final response = await messaging.sendEachForMulticast(
  MulticastMessage(
    tokens: ['<token-1>', '<token-2>', '<token-3>'],
    notification: Notification(title: 'Hello', body: 'World!'),
  ),
);
print('Sent: ${response.successCount}, Failed: ${response.failureCount}');

subscribeToTopic / unsubscribeFromTopic

// Subscribe tokens to a topic
await messaging.subscribeToTopic(['<token-1>', '<token-2>'], 'news');

// Unsubscribe tokens from a topic
await messaging.unsubscribeFromTopic(['<token-1>', '<token-2>'], 'news');

Storage

import 'dart:typed_data';
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
import 'package:google_cloud_storage/google_cloud_storage.dart' as gcs;

final app = FirebaseApp.initializeApp();
final storage = app.storage();
final bucket = storage.bucket('<bucket-name>');

insertObject (upload)

await bucket.storage.uploadObject(
  bucket.name,
  'path/to/file.txt',
  Uint8List.fromList('Hello, world!'.codeUnits),
  metadata: gcs.ObjectMetadata(contentType: 'text/plain'),
);

downloadObject

final bytes = await bucket.storage.downloadObject(bucket.name, 'path/to/file.txt');
print(String.fromCharCodes(bytes));

objectMetadata

final metadata = await bucket.storage.objectMetadata(bucket.name, 'path/to/file.txt');
print('Size: ${metadata.size} bytes');
print('Content type: ${metadata.contentType}');

deleteObject

await bucket.storage.deleteObject(bucket.name, 'path/to/file.txt');

getDownloadURL

Returns a long-lived public download URL backed by a Firebase download token, suitable for sharing with end-users.

final url = await storage.getDownloadURL(bucket, 'path/to/file.txt');
print('Download URL: $url');

Security Rules

import 'package:dart_firebase_admin/dart_firebase_admin.dart';

final app = FirebaseApp.initializeApp();
final securityRules = app.securityRules();

getFirestoreRuleset

final ruleset = await securityRules.getFirestoreRuleset();
print(ruleset.name);

releaseFirestoreRulesetFromSource

final source = '''
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}
''';

final ruleset = await securityRules.releaseFirestoreRulesetFromSource(source);
print('Applied ruleset: ${ruleset.name}');

getStorageRuleset

final ruleset = await securityRules.getStorageRuleset();
print(ruleset.name);

releaseStorageRulesetFromSource

final source = '''
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}
''';

final ruleset = await securityRules.releaseStorageRulesetFromSource(source);
print('Applied ruleset: ${ruleset.name}');

createRuleset / deleteRuleset

// Create a ruleset without applying it
const source = "rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if false; } } }";
final rulesFile = RulesFile(name: 'firestore.rules', content: source);
final ruleset = await securityRules.createRuleset(rulesFile);
print('Created ruleset: ${ruleset.name}');

// Delete a ruleset by name
await securityRules.deleteRuleset(ruleset.name);

Supported Services

The Firebase Admin Dart SDK currently supports the following Firebase services:

🟒 - Fully supported
🟑 - Partially supported / Work in progress
πŸ”΄ - Not supported

Service Status Notes
App 🟒
App Check 🟒
Authentication 🟒
Data Connect πŸ”΄
Realtime Database πŸ”΄
Event Arc πŸ”΄
Extensions πŸ”΄
Firestore 🟒 Excludes realtime capabilities
Functions 🟒
Installations πŸ”΄
Machine Learning πŸ”΄
Messaging 🟒
Project Management πŸ”΄
Remote Config πŸ”΄
Security Rules 🟒
Storage 🟒

Additional Packages

Alongside the Firebase Admin Dart SDK, this repository contains additional workspace/pub.dev packages to accomodate the SDK:

Contributing

Contributions are welcome! Please read the contributing guide to get started.

License

Apache License Version 2.0

About

πŸ”₯ A Firebase Admin SDK for Dart.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Contributors

Languages