Dart Firebase Admin
Welcome! This project is a port of Node’s Firebase Admin SDK to Dart.
⚠️ This project is still in its early stages, and some features may be missing or bugged. Currently, only Firestore is available, with more to come (auth next).
- Dart Firebase Admin
- Available features
- Usage
- Connecting to the SDK
- Connecting using the environment
- Connecting using a
service-account.json file
- Using Firestore
- Using Auth
Available features
| Firestore |
|
| reference.id |
✅ |
| reference.parent |
✅ |
| reference.path |
✅ |
| reference.== |
✅ |
| reference.withConverter |
✅ |
| collection.listDocuments |
✅ |
| collection.add |
✅ |
| collection.get |
✅ |
| collection.create |
✅ |
| collection.delete |
✅ |
| collection.set |
✅ |
| collection.update |
✅ |
| collection.collection |
✅ |
| query.where(‘field’, operator, value) |
✅ |
| query.where(‘field.path’, operator, value) |
✅ |
| query.where(FieldPath(‘…’), operator, value) |
✅ |
| query.whereFilter(Filter.and(a, b)) |
✅ |
| query.whereFilter(Filter.or(a, b)) |
✅ |
| query.startAt |
✅ |
| query.startAtDocument |
✅ |
| query.startAfter |
✅ |
| query.startAfterDocument |
✅ |
| query.endAt |
✅ |
| query.endAtDocument |
✅ |
| query.endAfter |
✅ |
| query.endAfterDocument |
✅ |
| query.onSnapshot |
❌ |
| query.select |
✅ |
| query.orderBy |
✅ |
| query.limit |
✅ |
| query.limitToLast |
✅ |
| query.offset |
✅ |
| querySnapshot.docs |
✅ |
| querySnapshot.readTime |
✅ |
| querySnapshot.docsChange |
⚠️ |
| documentSnapshots.data |
✅ |
| documentSnapshots.readTime/createTime/updateTime |
✅ |
| documentSnapshots.id |
✅ |
| documentSnapshots.exists |
✅ |
| documentSnapshots.data |
✅ |
| documentSnapshots.get(fieldPath) |
✅ |
| FieldValue.documentId |
✅ |
| FieldValue.increment |
✅ |
| FieldValue.arrayUnion |
✅ |
| FieldValue.arrayRemove |
✅ |
| FieldValue.delete |
✅ |
| FieldValue.serverTimestamp |
✅ |
| collectionGroup |
✅ |
| runTransaction |
❌ |
| GeoPoint |
✅ |
| Timestamp |
✅ |
| BundleBuilder |
❌ |
| Auth |
|
| auth.tenantManager |
❌ |
| auth.projectConfigManager |
❌ |
| auth.generatePasswordResetLink |
✅ |
| auth.generateEmailVerificationLink |
✅ |
| auth.generateVerifyAndChangeEmailLink |
✅ |
| auth.generateSignInWithEmailLink |
✅ |
| auth.listProviderConfigs |
✅ |
| auth.createProviderConfig |
✅ |
| auth.updateProviderConfig |
✅ |
| auth.getProviderConfig |
✅ |
| auth.deleteProviderConfig |
✅ |
| auth.createCustomToken |
✅ |
| auth.setCustomUserClaims |
✅ |
| auth.verifyIdToken |
✅ |
| auth.revokeRefreshTokens |
✅ |
| auth.createSessionCookie |
✅ |
| auth.verifySessionCookie |
✅ |
| auth.importUsers |
✅ |
| auth.listUsers |
✅ |
| auth.deleteUser |
✅ |
| auth.deleteUsers |
✅ |
| auth.getUser |
✅ |
| auth.getUserByPhoneNumber |
✅ |
| auth.getUserByEmail |
✅ |
| auth.getUserByProviderUid |
✅ |
| auth.getUsers |
✅ |
| auth.createUser |
✅ |
| auth.updateUser |
✅ |
Usage
Connecting to the SDK
Before using Firebase, we must first authenticate.
There are currently two options:
- You can connect using environment variables
- Alternatively, you can specify a
service-account.json file
Connecting using the environment
To connect using environment variables, you will need to have the Firebase CLI installed.
Once done, you can run:
And log-in to the project of your choice.
From there, you can have your Dart program authenticate using the environment with:
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
void main() {
final admin = FirebaseAdminApp.initializeApp(
'<your project name>',
// This will obtain authentication information from the environment
Credential.fromApplicationDefaultCredentials(),
);
// TODO use the Admin SDK
final firestore = Firestore(admin);
firestore.doc('hello/world').get();
}
Connecting using a service-account.json file
Alternatively, you can choose to use a service-account.json file.
This file can be obtained in your firebase console by going to:
https://console.firebase.google.com/u/0/project/<your-project-name>/settings/serviceaccounts/adminsdk
Make sure to replace <your-project-name> with the name of your project. One there, follow the steps and download the file. Place it anywhere you want in your project.
⚠️ Note: This file should be kept private. Do not commit it on public repositories.
After all of that is done, you can now authenticate in your Dart program using:
import 'package:dart_firebase_admin/dart_firebase_admin.dart';
void main() {
final admin = FirebaseAdminApp.initializeApp(
'<your project name>',
// Log-in using the newly downloaded file.
Credential.fromServiceAccount(
File('<path to your service-account.json file>'),
),
);
// TODO use the Admin SDK
final firestore = Firestore(admin);
firestore.doc('hello/world').get();
}
Using Firestore
First, make sure to follow the steps on how to authenticate. You should now have an instance of a FirebaseAdminApp object.
You can now use this object to create a Firestore object as followed:
// Obtained in the previous steps
FirebaseAdminApp admin;
final firestore = Firestore(admin);
From this point onwards, using Firestore with the admin ADK is roughly equivalent to using FlutterFire.
Using this Firestore object, you’ll find your usual collection/query/document objects.
For example, you can perform a where query:
// The following lists all users above 18 years old
final collection = firestore.collection('users');
final adults = collection.where('age', WhereFilter.greaterThan, 18);
final adultsSnapshot = await adults.get();
for (final adult in adultsSnapshot.docs) {
print(adult.data()['age']);
}
Composite queries are also supported:
// List users with either John or Jack as first name.
firestore
.collection('users')
.whereFilter(
Filter.or([
Filter.where('firstName', WhereFilter.equal, 'John'),
Filter.where('firstName', WhereFilter.equal, 'Jack'),
]),
);
Alternatively, you can fetch a specific document too:
// Print the age of the user with ID "123"
final user = await firestore.doc('users/123').get();
print(user.data()?['age']);
Using Auth
First, make sure to follow the steps on how to authenticate. You should now have an instance of a FirebaseAdminApp object.
You can now use this object to create a FirebaseAuth object as followed:
// Obtained in the previous steps
FirebaseAdminApp admin;
final auth = FirebaseAuth(admin);
You can then use this FirebaseAuth object to perform various auth operations. For example, you can generate a password reset link:
final link = await auth.generatePasswordResetLink(
'hello@example.com',
);
Download and/or contribute to this SDK source code on GitHub
🔥 A Firebase Admin SDK for Dart.
https://github.com/firebase/firebase-admin-dart
70 forks.
177 stars.
10 open issues.
Recent commits:
- fix(firestore): honour Settings.ssl when building the API endpoint (#316)`Settings.ssl` was a dead field. It was stored, carried through copyWith,and compared in == and hashCode, but nothing ever read it: the endpointwas built with `Uri.https(…)` unconditionally unlessFIRESTORE_EMULATOR_HOST was set. A custom `Settings.host` therefore couldnot be reached over plain HTTP, and `ssl: false` did nothing.The scheme now follows `Settings.ssl` on the non-emulator path.FIRESTORE_EMULATOR_HOST keeps precedence over both `host` and `ssl`,since it is the documented way to point the SDK at an emulator; only thecustom-host path changes behaviour. The default stays `ssl: true`, soproduction callers are unaffected.Note that test/fixtures/helpers.dart already passed `ssl: false` next toa custom host for emulator tests, and worked only because the separateFIRESTORE_EMULATOR_HOST branch happened to hardcode HTTP.Also corrects the `Settings.ssl` doc comment, which described behaviourthe field did not have.Co-authored-by: Ademola Fadumo <48495111+demolaf@users.noreply.github.com>, GitHub
- feat: add support for Firestore Pipeline (#292)* feat: add support for Firestore Pipeline* fix feedback* skip* fix(firestore): encode Pipeline field arguments as field referencesArguments in a "field or expression" position kept String values as stringliterals, so `PipelineFunctions.startsWith('title', 'Harry')` compared theliteral text "title" against "Harry" instead of reading the `title` field.Add `_fieldOrExpression`, mirroring the Node SDK's `fieldOrExpression`, andapply it across the function catalog. Value positions still keep Strings asliterals, and document paths stay values as they do in Node.Also:- Add `PipelineSource.createFrom()` to convert a `Query` or `VectorQuery` into an equivalent Pipeline, translating filters, projections, implicit orderings, cursors, limit/limitToLast and offset.- Add expressions released since the initial port: `coalesce`, `length`, `reverse`, `concat`, `getField`, `geoDistance`, `documentMatches` and `score`, plus `logicalMinimum`/`logicalMaximum`.- Align `PipelineExpression.length()` and `.concat()` with the Node SDK's generic `length`/`concat` backend functions, and expose the string-specific `charLength()`/`stringConcat()` alongside them.- Rename field-position parameters to `fieldName` to match Node.- Hide `greaterThan`/`lessThan` from the Firestore import in two suites that want the `matcher` versions.* test(firestore): cover createFrom field mask projection* fix(firestore): correct unnest, replaceWith, sample and distinct encodingsFour Pipeline stages diverged from the backend contract, verified againstthe canonical Node SDK stage definitions in dev/src/pipelines/stage.ts:- `unnest` sent only the array expression, so there was no way to name the emitted element. It now sends `[expr, field(alias)]`, taking the alias from the selectable, and encodes `index_field` as a field reference rather than a string.- `replace_with` omitted the required mode argument; it now sends `[map, 'full_replace']`.- `sample` passed the rate as a `documents`/`percentage` option; it now sends `[rate, mode]` with mode `documents` or `percent`.- `distinct` sent a positional list of expressions; it now sends a single map keyed by alias, reusing the same projection map as `select` and `aggregate`.`unnest` and `sample` are breaking signature changes.Also make `PipelineFunctions.minimum`/`maximum` aggregate-only, matchingNode, now that `logicalMinimum`/`logicalMaximum` cover the element-wiseform.Adds golden proto tests asserting each stage's arguments and options, sothis class of wire-format drift is caught without an Enterprise database.* docs(firestore): document and demonstrate every Pipeline stageThe README covered 4 of the ~16 Pipeline stages and the example directoryhad no pipeline content at all.- Add `example/pipeline_example.dart` covering every stage: source/filter/ sort/project/limit, aggregates with and without grouping, `unnest`, `replaceWith` with `addFields`/`removeFields`, `distinct`, `sample`, `union`, `findNearest`, and `createFrom`. Each example seeds and cleans up its own documents, and carries `[START]`/`[END]` region markers for docs ingestion.- Expand the README: every source and stage with a runnable snippet, a function reference table mapping Dart helpers to backend function names, the field-argument vs value-argument rule, execution options, the `PipelineSnapshot`/`PipelineResult` surface, and a Query migration guide.- Note the Enterprise-edition requirement and the failure behavior on `Pipeline.execute()` and `Firestore.pipeline()`.- Add `example/README.md` so both examples are discoverable, and so pub.dev's Example tab shows representative code.* test(firestore): fix false-positive Pipeline E2E expectations`equalAny('dart', Expression.field('tags'))` passed a bare String in afield position, where a String means a field reference rather than astring literal (mirroring the Node SDK's fieldOrExpression). It thereforeasked about a non-existent `dart` field, so equalAny was always false –and the adjacent notEqualAny passed for exactly the same wrong reason, amissing field trivially not equalling anything. Both now target `title`with array literals so they exercise the real semantics.Also require FIRESTORE_PIPELINE_E2E_DATABASE_ID explicitly rather thanfalling back to '(default)'. CI credential helpers such asgoogle-github-actions/auth export GOOGLE_CLOUD_PROJECT, so the previousproject-only guard could silently arm the suite against a defaultdatabase that lacks Pipelines support or this suite's vector index.* ci: run Firestore Pipeline E2E tests against a live databaseAdds e2e_pipeline.yml, which runs test/e2e/pipeline_e2e_test.dart againstthe Enterprise-edition firestore-pipeline-test database that FlutterFire'se2e_tests_pipeline.yaml also targets, so both SDKs are validated againstone shared Pipelines database. The suite existed but nothing ran it.Triggers on pull requests touching packages/google_cloud_firestore, onpushes to main, nightly, and on demand. Fork and dependabot pull requestsare skipped because they receive no secrets. It is a separate workflowrather than a build.yml job so the live-quota cost is only paid forchanges that can affect it.`dart test` exits 0 when every test is skipped, which is exactly what amissing project or database ID produces, so the job fails if the secretis empty and again if the run reports "All tests skipped" — otherwise amisconfigured job would report green for tests that never executed.Authenticates as a dedicated service account holding roles/datastore.userin the Pipelines project. The key is written to $RUNNER_TEMP rather thanthe checkout and removed in an always() step.* fix(firestore): encode documents() source paths relative to the databaseThe `documents` source stage routed each DocumentReference through_encodePipelineValue, which emits the full resource name(projects/{p}/databases/{d}/documents/books/book-1). Source stages nameresources by their path relative to the database instead: the `collection`stage one branch above already emitted `/${path}`, and Node'sDocumentsSource encodes `'/' + ref.path`. The full name is only correctfor references in a value position, so the path is now built at the stagerather than in the shared value encoder.Extracts the shared `_relativeReference` helper, updates the unit test,and adds E2E coverage for the stage, which was previously untested againsta live database.———Co-authored-by: Ademola Fadumo <48495111+demolaf@users.noreply.github.com>Co-authored-by: demolaf <demolafadumo@gmail.com>, GitHub
- fix(app): append usage tracking headers and avoid duplicating tokens (#315)* fix(app): append usage tracking headers and avoid duplicating tokensUpdate FirebaseUserAgentClient to append fireAdminApiClientTag to existingX-Goog-Api-Client headers rather than overwriting them, and avoid duplicatingruntime tokens.Bump version to 0.5.5-wip and update CHANGELOG.md.* test: add test verifying case-insensitive handling of lowercase headers* fix(app): use whitespace token boundary matching for fire-admin tagPrevent false-positive deduplication matches when existing headers containversion prefixes (e.g. fire-admin/0.5.50 or fire-admin/0.5.5-other)., GitHub
- chore(release): prepare firestore v0.5.3 and admin v0.5.4 (#313)Why this change is needed:Prepares non-breaking patch releases for google_cloud_firestore andfirebase_admin_sdk by dropping WIP staging suffixes and updating versionconstants after landing stability fixes and custom headers support.Summary of changes:* Bump google_cloud_firestore version to 0.5.3 in pubspec and changelog.* Remove -wip suffix from firebase_admin_sdk to stage release 0.5.4.* Add recent Storage.delete() idempotency bugfix item to changelog.* Regenerate version.g.dart constant to match 0.5.4., GitHub
- fix(storage): add idempotency guard to Storage.delete() (#312)Why this change is needed:Calling storage.delete() followed by app.close() double-closed the delegateHTTP client, triggering an unhandled async StateError during cleanup.Summary of changes:* Add an _isDeleted guard to Storage.delete() to prevent double closing.* Add multi-delete lifecycle unit test matching Firestore test patterns., GitHub
Provides the list of the opensource Flutter apps collection with GitHub repository.