11// ignore_for_file: public_member_api_docs
22
33import 'dart:async' ;
4+
45import 'package:core/core.dart' ;
5- import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart' ;
66import 'package:data_mongodb/data_mongodb.dart' ;
77import 'package:data_repository/data_repository.dart' ;
88import 'package:email_repository/email_repository.dart' ;
@@ -17,6 +17,7 @@ import 'package:flutter_news_app_api_server_full_source_code/src/services/dashbo
1717import 'package:flutter_news_app_api_server_full_source_code/src/services/database_migration_service.dart' ;
1818import 'package:flutter_news_app_api_server_full_source_code/src/services/database_seeding_service.dart' ;
1919import 'package:flutter_news_app_api_server_full_source_code/src/services/default_user_preference_limit_service.dart' ;
20+ import 'package:flutter_news_app_api_server_full_source_code/src/services/firebase_authenticator.dart' ;
2021import 'package:flutter_news_app_api_server_full_source_code/src/services/firebase_push_notification_client.dart' ;
2122import 'package:flutter_news_app_api_server_full_source_code/src/services/jwt_auth_token_service.dart' ;
2223import 'package:flutter_news_app_api_server_full_source_code/src/services/mongodb_rate_limit_service.dart' ;
@@ -86,6 +87,7 @@ class AppDependencies {
8687 late final RateLimitService rateLimitService;
8788 late final CountryQueryService countryQueryService;
8889 late final IPushNotificationService pushNotificationService;
90+ late final IFirebaseAuthenticator firebaseAuthenticator;
8991 late final IPushNotificationClient firebasePushNotificationClient;
9092 late final IPushNotificationClient oneSignalPushNotificationClient;
9193
@@ -115,56 +117,6 @@ class AppDependencies {
115117 /// The core logic for initializing all dependencies.
116118 /// This method is private and should only be called once by [init] .
117119 Future <void > _initializeDependencies () async {
118- Future <String ?> getFirebaseAccessToken () async {
119- try {
120- // Step 1: Create and sign the JWT.
121- final pem = EnvironmentConfig .firebasePrivateKey.replaceAll (
122- r'\n' ,
123- '\n ' ,
124- );
125- final privateKey = RSAPrivateKey (pem);
126- final jwt = JWT (
127- {'scope' : 'https://www.googleapis.com/auth/cloud-platform' },
128- issuer: EnvironmentConfig .firebaseClientEmail,
129- audience: Audience .one ('https://oauth2.googleapis.com/token' ),
130- );
131- final signedToken = jwt.sign (
132- privateKey,
133- algorithm: JWTAlgorithm .RS256 ,
134- expiresIn: const Duration (minutes: 5 ),
135- );
136-
137- // Step 2: Exchange the JWT for an access token.
138- final tokenClient = HttpClient (
139- baseUrl: 'https://oauth2.googleapis.com' ,
140- // The tokenProvider for this client is null because this request
141- // does not use a Bearer token.
142- tokenProvider: () async => null ,
143- );
144-
145- final response = await tokenClient.post <Map <String , dynamic >>(
146- '/token' ,
147- data: {
148- 'grant_type' : 'urn:ietf:params:oauth:grant-type:jwt-bearer' ,
149- 'assertion' : signedToken,
150- },
151- );
152-
153- final accessToken = response['access_token' ] as String ? ;
154- if (accessToken == null ) {
155- throw const OperationFailedException (
156- 'Could not retrieve Firebase access token.' ,
157- );
158- }
159- return accessToken;
160- } catch (e, s) {
161- _log.severe ('Error during Firebase token exchange: $e ' , e, s);
162- throw OperationFailedException (
163- 'Failed to authenticate with Firebase: $e ' ,
164- );
165- }
166- }
167-
168120 _log.info ('Initializing application dependencies...' );
169121 try {
170122 // 1. Initialize Database Connection
@@ -277,6 +229,13 @@ class AppDependencies {
277229 logger: Logger ('DataMongodb<PushNotificationSubscription>' ),
278230 );
279231
232+ // --- Initialize Firebase Authenticator ---
233+ // This dedicated service encapsulates the logic for obtaining a Firebase
234+ // access token, keeping the dependency setup clean.
235+ firebaseAuthenticator = FirebaseAuthenticator (
236+ log: Logger ('FirebaseAuthenticator' ),
237+ );
238+
280239 // --- Initialize HTTP clients for push notification providers ---
281240
282241 // The Firebase client requires a short-lived OAuth2 access token. This
@@ -286,7 +245,7 @@ class AppDependencies {
286245 final firebaseHttpClient = HttpClient (
287246 baseUrl:
288247 'https://fcm.googleapis.com/v1/projects/${EnvironmentConfig .firebaseProjectId }/' ,
289- tokenProvider: getFirebaseAccessToken ,
248+ tokenProvider: firebaseAuthenticator.getAccessToken ,
290249 logger: Logger ('FirebasePushNotificationClient' ),
291250 );
292251
0 commit comments