Skip to content

Commit 89b7842

Browse files
demolafkevmoo
andauthored
feat: extension on FirebaseApp for serviceAccountEmail() and sign() apis (#171)
* Update packages for googleapis_auth breaking changes Accommodate breaking changes from googleapis_auth, specifically the removal of the `serviceAccountCredentials` getter and the refactoring of cryptographic signing. - Update `AuthClient.sign()` usages across dart_firebase_admin and googleapis_storage. The method now returns a `Future<String>` (base64-encoded signature) instead of an object with a `signedBlob` property. - Explicitly pass `serviceAccountCredentials` into `sign()` invocations where available to maintain local RSA signing capabilities. - Remove `serviceAccountCredentials` overrides from EmulatorClient implementations in dart_firebase_admin, googleapis_storage, and googleapis_firestore. - Update Compute Engine environment detection in FunctionsRequestHandler to check internal credential options instead of the removed AuthClient.serviceAccountCredentials. - Delete local AuthExtension helpers in dart_firebase_admin and googleapis_storage, migrating to the newly provided AuthClientSigningExtension methods. - Update authClient.getServiceAccountEmail usages from a getter to a method invocation. * OVERRIDES for in-flight PR Will replace when google/googleapis.dart#717 lands * test: fix functions test mock for metadata server email resolution * feat: add extension methods for FirebaseApp to handle service account email and signing * chore: bump dart_firebase_admin to 0.5.0 and googleapis_auth dependency to 2.1.0 * chore: update changelog --------- Co-authored-by: Kevin Moore <kevmoo@google.com>
1 parent 4304fa3 commit 89b7842

File tree

17 files changed

+83
-37
lines changed

17 files changed

+83
-37
lines changed

packages/dart_firebase_admin/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 1.0.0-beta.1 - 2026-02-12
1+
## 0.5.0 - 2026-02-12
22

33
- Major changes
44

packages/dart_firebase_admin/lib/src/app/app_registry.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,7 @@ class AppRegistry {
100100

101101
final config = env['FIREBASE_CONFIG'];
102102
if (config == null || config.isEmpty) {
103-
return AppOptions(
104-
credential: Credential.fromApplicationDefaultCredentials(),
105-
);
103+
return AppOptions(credential: _credentialFromEnv(env));
106104
}
107105

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

120118
return AppOptions(
121-
credential: Credential.fromApplicationDefaultCredentials(),
119+
credential: _credentialFromEnv(env),
122120
projectId: json['projectId'] as String?,
123121
databaseURL: json['databaseURL'] as String?,
124122
storageBucket: json['storageBucket'] as String?,
@@ -186,4 +184,17 @@ class AppRegistry {
186184
);
187185
}
188186
}
187+
188+
Credential _credentialFromEnv(Map<String, String> env) {
189+
final googleCredPath = env['GOOGLE_APPLICATION_CREDENTIALS'];
190+
if (googleCredPath != null) {
191+
try {
192+
return Credential.fromServiceAccount(File(googleCredPath));
193+
} catch (_) {
194+
// File missing, not a service account JSON, or missing project_id –
195+
// fall through to ADC.
196+
}
197+
}
198+
return Credential.fromApplicationDefaultCredentials();
199+
}
189200
}

packages/dart_firebase_admin/lib/src/app_check/token_generator.dart

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:googleapis_auth/auth_io.dart' as googleapis_auth;
44
import 'package:meta/meta.dart';
55

66
import '../../dart_firebase_admin.dart';
7+
import '../utils/app_extension.dart';
78
import 'app_check.dart';
89
import 'app_check_api.dart';
910

@@ -31,8 +32,7 @@ class AppCheckTokenGenerator {
3132
AppCheckTokenOptions? options,
3233
]) async {
3334
try {
34-
final authClient = await app.client;
35-
final account = await authClient.getServiceAccountEmail();
35+
final account = await app.serviceAccountEmail;
3636

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

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

50-
final signature = await authClient.sign(
51-
utf8.encode(token),
52-
serviceAccountCredentials:
53-
app.options.credential?.serviceAccountCredentials,
54-
);
50+
final signature = await app.sign(utf8.encode(token));
5551

5652
return '$token.$signature';
5753
} on googleapis_auth.ServerRequestFailedException catch (err) {

packages/dart_firebase_admin/lib/src/auth.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:meta/meta.dart';
1414

1515
import 'app.dart';
1616
import 'object_utils.dart';
17+
import 'utils/app_extension.dart';
1718
import 'utils/jwt.dart';
1819
import 'utils/utils.dart';
1920
import 'utils/validator.dart';

packages/dart_firebase_admin/lib/src/auth/token_generator.dart

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ class _FirebaseTokenGenerator {
7070
}
7171

7272
try {
73-
final authClient = await _app.client;
74-
final account = await authClient.getServiceAccountEmail();
73+
final account = await _app.serviceAccountEmail;
7574

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

8988
final token = '${_encodeSegment(header)}.${_encodeSegment(body)}';
90-
final signature = await authClient.sign(
91-
utf8.encode(token),
92-
serviceAccountCredentials:
93-
_app.options.credential?.serviceAccountCredentials,
94-
);
89+
final signature = await _app.sign(utf8.encode(token));
9590

9691
return '$token.$signature';
9792
} on googleapis_auth.ServerRequestFailedException catch (err, stack) {

packages/dart_firebase_admin/lib/src/functions/functions.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:googleapis_auth/auth_io.dart' as googleapis_auth;
55
import 'package:meta/meta.dart';
66

77
import '../app.dart';
8+
import '../utils/app_extension.dart';
89
import '../utils/validator.dart';
910

1011
part 'functions_api.dart';

packages/dart_firebase_admin/lib/src/functions/functions_request_handler.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ class FunctionsRequestHandler {
274274

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

279279
if (serviceAccountEmail.isEmpty) {
280280
throw FirebaseFunctionsAdminException(
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:googleapis_auth/auth_io.dart';
2+
3+
import '../app.dart';
4+
5+
extension AppExtension on FirebaseApp {
6+
Future<String> get serviceAccountEmail async =>
7+
options.credential?.serviceAccountCredentials?.email ??
8+
(await client).getServiceAccountEmail();
9+
10+
/// Signs the given data using the IAM Credentials API or local credentials.
11+
///
12+
/// Returns a base64-encoded signature string. In emulator mode, returns an
13+
/// empty string to produce unsigned tokens.
14+
Future<String> sign(List<int> data, {String? endpoint}) async =>
15+
Environment.isAuthEmulatorEnabled()
16+
? ''
17+
: (await client).sign(
18+
data,
19+
serviceAccountCredentials:
20+
options.credential?.serviceAccountCredentials,
21+
endpoint: endpoint,
22+
);
23+
}

packages/dart_firebase_admin/lib/version.g.dart

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/dart_firebase_admin/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: dart_firebase_admin
22
description: A Firebase Admin SDK implementation for Dart.
33
resolution: workspace
4-
version: 1.0.0-beta.1
4+
version: 0.5.0
55
homepage: "https://github.com/invertase/dart_firebase_admin"
66
repository: "https://github.com/invertase/dart_firebase_admin"
77
publish_to: none
@@ -16,7 +16,7 @@ dependencies:
1616
equatable: ^2.0.7
1717
google_cloud: ^0.3.0
1818
googleapis: ^15.0.0
19-
googleapis_auth: ^2.1.0-beta.1
19+
googleapis_auth: ^2.1.0
2020
googleapis_beta: ^9.0.0
2121
googleapis_firestore: ^0.1.0
2222
googleapis_storage: ^0.1.0

0 commit comments

Comments
 (0)