@@ -3,6 +3,7 @@ import 'package:ht_api/src/services/auth_token_service.dart';
33import 'package:ht_api/src/services/token_blacklist_service.dart' ;
44import 'package:ht_data_repository/ht_data_repository.dart' ;
55import 'package:ht_shared/ht_shared.dart' ;
6+ import 'package:logging/logging.dart' ;
67import 'package:uuid/uuid.dart' ;
78
89/// {@template jwt_auth_token_service}
@@ -23,13 +24,16 @@ class JwtAuthTokenService implements AuthTokenService {
2324 required HtDataRepository <User > userRepository,
2425 required TokenBlacklistService blacklistService,
2526 required Uuid uuidGenerator,
27+ required Logger log,
2628 }) : _userRepository = userRepository,
2729 _blacklistService = blacklistService,
28- _uuid = uuidGenerator;
30+ _uuid = uuidGenerator,
31+ _log = log;
2932
3033 final HtDataRepository <User > _userRepository;
3134 final TokenBlacklistService _blacklistService;
3235 final Uuid _uuid;
36+ final Logger _log;
3337
3438 // --- Configuration ---
3539
@@ -76,10 +80,10 @@ class JwtAuthTokenService implements AuthTokenService {
7680 expiresIn: _tokenExpiryDuration, // Redundant but safe
7781 );
7882
79- print ('Generated JWT for user ${user .id }' );
83+ _log. info ('Generated JWT for user ${user .id }' );
8084 return token;
8185 } catch (e) {
82- print ('Error generating JWT for user ${user .id }: $e ' );
86+ _log. severe ('Error generating JWT for user ${user .id }: $e ' );
8387 // Map to a standard exception
8488 throw OperationFailedException (
8589 'Failed to generate authentication token: $e ' ,
@@ -89,18 +93,18 @@ class JwtAuthTokenService implements AuthTokenService {
8993
9094 @override
9195 Future <User ?> validateToken (String token) async {
92- print ('[validateToken] Attempting to validate token...' );
96+ _log. finer ('[validateToken] Attempting to validate token...' );
9397 try {
9498 // Verify the token's signature and expiry
95- print ('[validateToken] Verifying token signature and expiry...' );
99+ _log. finer ('[validateToken] Verifying token signature and expiry...' );
96100 final jwt = JWT .verify (token, SecretKey (_secretKey));
97- print ('[validateToken] Token verified. Payload: ${jwt .payload }' );
101+ _log. finer ('[validateToken] Token verified. Payload: ${jwt .payload }' );
98102
99103 // --- Blacklist Check ---
100104 // Extract the JWT ID (jti) claim
101105 final jti = jwt.payload['jti' ] as String ? ;
102106 if (jti == null || jti.isEmpty) {
103- print (
107+ _log. warning (
104108 '[validateToken] Token validation failed: Missing or empty "jti" claim.' ,
105109 );
106110 // Throw specific exception for malformed token
@@ -109,21 +113,21 @@ class JwtAuthTokenService implements AuthTokenService {
109113 );
110114 }
111115
112- print ('[validateToken] Checking blacklist for jti: $jti ' );
116+ _log. finer ('[validateToken] Checking blacklist for jti: $jti ' );
113117 final isBlacklisted = await _blacklistService.isBlacklisted (jti);
114118 if (isBlacklisted) {
115- print (
119+ _log. warning (
116120 '[validateToken] Token validation failed: Token is blacklisted (jti: $jti ).' ,
117121 );
118122 // Throw specific exception for blacklisted token
119123 throw const UnauthorizedException ('Token has been invalidated.' );
120124 }
121- print ('[validateToken] Token is not blacklisted (jti: $jti ).' );
125+ _log. finer ('[validateToken] Token is not blacklisted (jti: $jti ).' );
122126 // --- End Blacklist Check ---
123127
124128 // Extract user ID from the subject claim ('sub')
125129 final subClaim = jwt.payload['sub' ];
126- print (
130+ _log. finer (
127131 '[validateToken] Extracted "sub" claim: $subClaim '
128132 '(Type: ${subClaim .runtimeType })' ,
129133 );
@@ -132,12 +136,12 @@ class JwtAuthTokenService implements AuthTokenService {
132136 String ? userId;
133137 if (subClaim is String ) {
134138 userId = subClaim;
135- print (
139+ _log. finer (
136140 '[validateToken] "sub" claim successfully cast to String: $userId ' ,
137141 );
138142 } else if (subClaim != null ) {
139143 // Treat non-string sub as an error
140- print (
144+ _log. severe (
141145 '[validateToken] ERROR: "sub" claim is not a String '
142146 '(Type: ${subClaim .runtimeType }).' ,
143147 );
@@ -148,7 +152,7 @@ class JwtAuthTokenService implements AuthTokenService {
148152 }
149153
150154 if (userId == null || userId.isEmpty) {
151- print (
155+ _log. warning (
152156 '[validateToken] Token validation failed: Missing or empty "sub" claim.' ,
153157 );
154158 // Throw specific exception for malformed token
@@ -157,27 +161,27 @@ class JwtAuthTokenService implements AuthTokenService {
157161 );
158162 }
159163
160- print ('[validateToken] Attempting to fetch user with ID: $userId ' );
164+ _log. finer ('[validateToken] Attempting to fetch user with ID: $userId ' );
161165 // Fetch the full user object from the repository
162166 // This ensures the user still exists and is valid
163167 final user = await _userRepository.read (id: userId);
164- print ('[validateToken] User repository read successful for ID: $userId ' );
165- print ('[validateToken] Token validated successfully for user ${user .id }' );
168+ _log. finer ('[validateToken] User repository read successful for ID: $userId ' );
169+ _log. info ('[validateToken] Token validated successfully for user ${user .id }' );
166170 return user;
167171 } on JWTExpiredException catch (e, s) {
168- print ('[validateToken] CATCH JWTExpiredException: Token expired. $ e \n $ s ' );
172+ _log. warning ('[validateToken] Token expired.' , e, s );
169173 // Throw the standardized exception instead of rethrowing the specific one
170174 throw const UnauthorizedException ('Token expired.' );
171175 } on JWTInvalidException catch (e, s) {
172- print (
176+ _log. warning (
173177 '[validateToken] CATCH JWTInvalidException: Invalid token. '
174178 'Reason: ${e .message }\n $s ' ,
175179 );
176180 // Throw specific exception for invalid token signature/format
177181 throw UnauthorizedException ('Invalid token: ${e .message }' );
178182 } on JWTException catch (e, s) {
179183 // Use JWTException as the general catch-all for other JWT issues
180- print (
184+ _log. warning (
181185 '[validateToken] CATCH JWTException: General JWT error. '
182186 'Reason: ${e .message }\n $s ' ,
183187 );
@@ -186,15 +190,15 @@ class JwtAuthTokenService implements AuthTokenService {
186190 } on HtHttpException catch (e, s) {
187191 // Handle errors from the user repository (e.g., user not found)
188192 // or blacklist check (if it threw HtHttpException)
189- print (
193+ _log. warning (
190194 '[validateToken] CATCH HtHttpException: Error during validation. '
191195 'Type: ${e .runtimeType }, Message: $e \n $s ' ,
192196 );
193197 // Re-throw repository/blacklist exceptions directly
194198 rethrow ;
195199 } catch (e, s) {
196200 // Catch unexpected errors during validation
197- print ('[validateToken] CATCH UNEXPECTED Exception: $ e \n $ s ' );
201+ _log. severe ('[validateToken] CATCH UNEXPECTED Exception' , e, s );
198202 // Wrap unexpected errors in a standard exception type
199203 throw OperationFailedException (
200204 'Token validation failed unexpectedly: $e ' ,
@@ -204,33 +208,33 @@ class JwtAuthTokenService implements AuthTokenService {
204208
205209 @override
206210 Future <void > invalidateToken (String token) async {
207- print ('[invalidateToken] Attempting to invalidate token...' );
211+ _log. finer ('[invalidateToken] Attempting to invalidate token...' );
208212 try {
209213 // 1. Verify the token signature FIRST, but ignore expiry for blacklisting
210214 // We want to blacklist even if it's already expired, to be safe.
211- print ('[invalidateToken] Verifying token signature (ignoring expiry)...' );
215+ _log. finer ('[invalidateToken] Verifying signature (ignoring expiry)...' );
212216 final jwt = JWT .verify (
213217 token,
214218 SecretKey (_secretKey),
215219 checkExpiresIn: false , // IMPORTANT: Don't fail if expired here
216220 checkHeaderType: true , // Keep other standard checks
217221 );
218- print ('[invalidateToken] Token signature verified.' );
222+ _log. finer ('[invalidateToken] Token signature verified.' );
219223
220224 // 2. Extract JTI (JWT ID)
221225 final jti = jwt.payload['jti' ] as String ? ;
222226 if (jti == null || jti.isEmpty) {
223- print ('[invalidateToken] Failed: Missing or empty "jti" claim.' );
227+ _log. warning ('[invalidateToken] Failed: Missing or empty "jti" claim.' );
224228 throw const InvalidInputException (
225229 'Cannot invalidate token: Missing or empty JWT ID (jti) claim.' ,
226230 );
227231 }
228- print ('[invalidateToken] Extracted jti: $jti ' );
232+ _log. finer ('[invalidateToken] Extracted jti: $jti ' );
229233
230234 // 3. Extract Expiry Time (exp)
231235 final expClaim = jwt.payload['exp' ];
232236 if (expClaim == null || expClaim is ! int ) {
233- print ('[invalidateToken] Failed: Missing or invalid "exp" claim.' );
237+ _log. warning ('[invalidateToken] Failed: Missing or invalid "exp" claim.' );
234238 throw const InvalidInputException (
235239 'Cannot invalidate token: Missing or invalid expiry (exp) claim.' ,
236240 );
@@ -239,31 +243,31 @@ class JwtAuthTokenService implements AuthTokenService {
239243 expClaim * 1000 ,
240244 isUtc: true ,
241245 );
242- print ('[invalidateToken] Extracted expiry: $expiryDateTime ' );
246+ _log. finer ('[invalidateToken] Extracted expiry: $expiryDateTime ' );
243247
244248 // 4. Add JTI to the blacklist
245- print ('[invalidateToken] Adding jti $jti to blacklist...' );
249+ _log. finer ('[invalidateToken] Adding jti $jti to blacklist...' );
246250 await _blacklistService.blacklist (jti, expiryDateTime);
247- print ('[invalidateToken] Token (jti: $jti ) successfully blacklisted.' );
251+ _log. info ('[invalidateToken] Token (jti: $jti ) successfully blacklisted.' );
248252 } on JWTException catch (e, s) {
249253 // Catch errors during the initial verification (e.g., bad signature)
250- print (
254+ _log. warning (
251255 '[invalidateToken] CATCH JWTException: Invalid token format/signature. '
252256 'Reason: ${e .message }\n $s ' ,
253257 );
254258 // Treat as invalid input for invalidation purposes
255259 throw InvalidInputException ('Invalid token format: ${e .message }' );
256260 } on HtHttpException catch (e, s) {
257261 // Catch errors from the blacklist service itself
258- print (
262+ _log. warning (
259263 '[invalidateToken] CATCH HtHttpException: Error during blacklisting. '
260264 'Type: ${e .runtimeType }, Message: $e \n $s ' ,
261265 );
262266 // Re-throw blacklist service exceptions
263267 rethrow ;
264268 } catch (e, s) {
265269 // Catch unexpected errors
266- print ('[invalidateToken] CATCH UNEXPECTED Exception: $ e \n $ s ' );
270+ _log. severe ('[invalidateToken] CATCH UNEXPECTED Exception' , e, s );
267271 throw OperationFailedException (
268272 'Token invalidation failed unexpectedly: $e ' ,
269273 );
0 commit comments