Skip to content

Commit e6c4e6b

Browse files
committed
refactor(service): replace print statements with structured logging
Refactors the `JwtAuthTokenService` to use a `Logger` instance for structured logging, replacing all previous `print()` calls.
1 parent 53e8a32 commit e6c4e6b

File tree

1 file changed

+38
-34
lines changed

1 file changed

+38
-34
lines changed

lib/src/services/jwt_auth_token_service.dart

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:ht_api/src/services/auth_token_service.dart';
33
import 'package:ht_api/src/services/token_blacklist_service.dart';
44
import 'package:ht_data_repository/ht_data_repository.dart';
55
import 'package:ht_shared/ht_shared.dart';
6+
import 'package:logging/logging.dart';
67
import '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

Comments
 (0)