Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/dart_firebase_admin/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## 1.0.0-beta.1 - 2026-02-12
## 0.5.0 - 2026-02-12

- Major changes

Expand Down
19 changes: 15 additions & 4 deletions packages/dart_firebase_admin/lib/src/app/app_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,7 @@ class AppRegistry {

final config = env['FIREBASE_CONFIG'];
if (config == null || config.isEmpty) {
return AppOptions(
credential: Credential.fromApplicationDefaultCredentials(),
);
return AppOptions(credential: _credentialFromEnv(env));
}

try {
Expand All @@ -118,7 +116,7 @@ class AppRegistry {
final json = jsonDecode(contents) as Map<String, dynamic>;

return AppOptions(
credential: Credential.fromApplicationDefaultCredentials(),
credential: _credentialFromEnv(env),
projectId: json['projectId'] as String?,
databaseURL: json['databaseURL'] as String?,
storageBucket: json['storageBucket'] as String?,
Expand Down Expand Up @@ -186,4 +184,17 @@ class AppRegistry {
);
}
}

Credential _credentialFromEnv(Map<String, String> env) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it could/should be in google_cloud right?

Maybe not right now...

Copy link
Copy Markdown
Member Author

@demolaf demolaf Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should actually, currently google_cloud handles obtaining projectId via computeProjectId.

It would be nice to have for credentials also, googleapis_auth would benefit from it too I believe.

final googleCredPath = env['GOOGLE_APPLICATION_CREDENTIALS'];
if (googleCredPath != null) {
try {
return Credential.fromServiceAccount(File(googleCredPath));
} catch (_) {
// File missing, not a service account JSON, or missing project_id –
// fall through to ADC.
}
}
return Credential.fromApplicationDefaultCredentials();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:googleapis_auth/auth_io.dart' as googleapis_auth;
import 'package:meta/meta.dart';

import '../../dart_firebase_admin.dart';
import '../utils/app_extension.dart';
import 'app_check.dart';
import 'app_check_api.dart';

Expand Down Expand Up @@ -31,8 +32,7 @@ class AppCheckTokenGenerator {
AppCheckTokenOptions? options,
]) async {
try {
final authClient = await app.client;
final account = await authClient.getServiceAccountEmail();
final account = await app.serviceAccountEmail;

final header = {'alg': 'RS256', 'typ': 'JWT'};
final iat = (DateTime.now().millisecondsSinceEpoch / 1000).floor();
Expand All @@ -47,11 +47,7 @@ class AppCheckTokenGenerator {

final token = '${_encodeSegment(header)}.${_encodeSegment(body)}';

final signature = await authClient.sign(
utf8.encode(token),
serviceAccountCredentials:
app.options.credential?.serviceAccountCredentials,
);
final signature = await app.sign(utf8.encode(token));

return '$token.$signature';
} on googleapis_auth.ServerRequestFailedException catch (err) {
Expand Down
1 change: 1 addition & 0 deletions packages/dart_firebase_admin/lib/src/auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:meta/meta.dart';

import 'app.dart';
import 'object_utils.dart';
import 'utils/app_extension.dart';
import 'utils/jwt.dart';
import 'utils/utils.dart';
import 'utils/validator.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ class _FirebaseTokenGenerator {
}

try {
final authClient = await _app.client;
final account = await authClient.getServiceAccountEmail();
final account = await _app.serviceAccountEmail;

final header = {'alg': 'RS256', 'typ': 'JWT'};
final iat = DateTime.now().millisecondsSinceEpoch ~/ 1000;
Expand All @@ -87,11 +86,7 @@ class _FirebaseTokenGenerator {
};

final token = '${_encodeSegment(header)}.${_encodeSegment(body)}';
final signature = await authClient.sign(
utf8.encode(token),
serviceAccountCredentials:
_app.options.credential?.serviceAccountCredentials,
);
final signature = await _app.sign(utf8.encode(token));

return '$token.$signature';
} on googleapis_auth.ServerRequestFailedException catch (err, stack) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:googleapis_auth/auth_io.dart' as googleapis_auth;
import 'package:meta/meta.dart';

import '../app.dart';
import '../utils/app_extension.dart';
import '../utils/validator.dart';

part 'functions_api.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ class FunctionsRequestHandler {

// Default: Use OIDC token with service account email.
// Try to get service account email from credential first, then from metadata service.
final serviceAccountEmail = await authClient.getServiceAccountEmail();
final serviceAccountEmail = await _httpClient.app.serviceAccountEmail;

if (serviceAccountEmail.isEmpty) {
throw FirebaseFunctionsAdminException(
Expand Down
23 changes: 23 additions & 0 deletions packages/dart_firebase_admin/lib/src/utils/app_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:googleapis_auth/auth_io.dart';

import '../app.dart';

extension AppExtension on FirebaseApp {
Future<String> get serviceAccountEmail async =>
options.credential?.serviceAccountCredentials?.email ??
(await client).getServiceAccountEmail();

/// Signs the given data using the IAM Credentials API or local credentials.
///
/// Returns a base64-encoded signature string. In emulator mode, returns an
/// empty string to produce unsigned tokens.
Future<String> sign(List<int> data, {String? endpoint}) async =>
Environment.isAuthEmulatorEnabled()
? ''
: (await client).sign(
data,
serviceAccountCredentials:
options.credential?.serviceAccountCredentials,
endpoint: endpoint,
);
}
2 changes: 1 addition & 1 deletion packages/dart_firebase_admin/lib/version.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/dart_firebase_admin/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: dart_firebase_admin
description: A Firebase Admin SDK implementation for Dart.
resolution: workspace
version: 1.0.0-beta.1
version: 0.5.0
homepage: "https://github.com/invertase/dart_firebase_admin"
repository: "https://github.com/invertase/dart_firebase_admin"
publish_to: none
Expand All @@ -16,7 +16,7 @@ dependencies:
equatable: ^2.0.7
google_cloud: ^0.3.0
googleapis: ^15.0.0
googleapis_auth: ^2.1.0-beta.1
googleapis_auth: ^2.1.0
googleapis_beta: ^9.0.0
googleapis_firestore: ^0.1.0
googleapis_storage: ^0.1.0
Expand Down
9 changes: 8 additions & 1 deletion packages/dart_firebase_admin/test/auth/auth_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@ import 'package:mocktail/mocktail.dart';
import 'package:test/test.dart';
import '../helpers.dart';
import '../mock.dart';
import '../mock_service_account.dart';

void main() {
late Auth auth;

setUp(() {
final sdk = createApp();
final sdk = createApp(
credential: Credential.fromServiceAccountParams(
privateKey: mockPrivateKey,
email: mockClientEmail,
projectId: projectId,
),
);
auth = Auth.internal(sdk);
});

Expand Down
7 changes: 6 additions & 1 deletion packages/dart_firebase_admin/test/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ FirebaseApp createApp({
FutureOr<void> Function()? tearDown,
googleapis_auth.AuthClient? client,
String? name,
Credential? credential,
}) {
final app = FirebaseApp.initializeApp(
name: name,
options: AppOptions(projectId: projectId, httpClient: client),
options: AppOptions(
projectId: projectId,
httpClient: client,
credential: credential,
),
);

addTearDown(() async {
Expand Down
2 changes: 1 addition & 1 deletion packages/googleapis_firestore/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
collection: ^1.18.0
google_cloud: ^0.3.0
googleapis: ^15.0.0
googleapis_auth: ^2.0.0
googleapis_auth: ^2.1.0
http: ^1.0.0
intl: ^0.20.0
meta: ^1.9.1
Expand Down
8 changes: 7 additions & 1 deletion packages/googleapis_storage/lib/src/file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,8 @@ class BucketFile extends ServiceObject<FileMetadata>
final authClient = await storage.authClient;
final signature = await authClient.sign(
policyStringBytes,
serviceAccountCredentials:
bucket.storage.options.credential?.serviceAccountCredentials,
endpoint: options.signingEndpoint?.toString(),
);

Expand Down Expand Up @@ -1056,7 +1058,9 @@ class BucketFile extends ServiceObject<FileMetadata>

// Get auth client and credentials
final authClient = await storage.authClient;
final clientEmail = await authClient.getServiceAccountEmail();
final clientEmail =
bucket.storage.options.credential?.serviceAccountCredentials?.email ??
await authClient.getServiceAccountEmail();

// Build credential string
final todayISO = _formatDateStamp(now);
Expand Down Expand Up @@ -1098,6 +1102,8 @@ class BucketFile extends ServiceObject<FileMetadata>
try {
final signature = await authClient.sign(
policyStringBytes,
serviceAccountCredentials:
bucket.storage.options.credential?.serviceAccountCredentials,
endpoint: options.signingEndpoint?.toString(),
);

Expand Down
12 changes: 10 additions & 2 deletions packages/googleapis_storage/lib/src/signer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,14 @@ class URLSigner {
final authClient = await bucket.storage.authClient;
final signature = await authClient.sign(
utf8.encode(blobToSign),
serviceAccountCredentials:
bucket.storage.options.credential?.serviceAccountCredentials,
endpoint: config.signedConfig.signingEndpoint?.toString(),
);

final clientEmail = await authClient.getServiceAccountEmail();
final clientEmail =
bucket.storage.options.credential?.serviceAccountCredentials?.email ??
await authClient.getServiceAccountEmail();

return {
'GoogleAccessId': clientEmail,
Expand Down Expand Up @@ -202,7 +206,9 @@ class URLSigner {

final authClient = await bucket.storage.authClient;

final clientEmail = await authClient.getServiceAccountEmail();
final clientEmail =
bucket.storage.options.credential?.serviceAccountCredentials?.email ??
await authClient.getServiceAccountEmail();

final credentialString = '$clientEmail/$credentialScope';
final dateISO = _formatAsUTCISO(config.accessibleAt, includeTime: true);
Expand Down Expand Up @@ -239,6 +245,8 @@ class URLSigner {

final signature = await authClient.sign(
utf8.encode(blobToSign),
serviceAccountCredentials:
bucket.storage.options.credential?.serviceAccountCredentials,
endpoint: config.signedConfig.signingEndpoint?.toString(),
);

Expand Down
2 changes: 1 addition & 1 deletion packages/googleapis_storage/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ environment:
sdk: ">=3.9.0 <4.0.0"

dependencies:
googleapis_auth: ^2.0.0
googleapis_auth: ^2.1.0
googleapis: ^15.0.0
google_cloud: ^0.3.0
http: ^1.6.0
Expand Down
7 changes: 0 additions & 7 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ dev_dependencies:
melos: ^7.3.0
test: ^1.26.3

dependency_overrides:
googleapis_auth:
git:
url: https://github.com/google/googleapis.dart.git
ref: drop_signer_class
path: googleapis_auth

workspace:
- packages/dart_firebase_admin
- packages/googleapis_firestore
Expand Down
Loading