@@ -179,6 +179,10 @@ async def refresh(
179179 or not is_valid_jwt_format (refresh_token .refresh )
180180 ):
181181 increment_auth_failure ("invalid_token" , "refresh_token" )
182+ category_logger .warning (
183+ "Refresh attempted with invalid token format" ,
184+ LogCategory .AUTH ,
185+ )
182186 raise HTTPException (
183187 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
184188 )
@@ -226,6 +230,11 @@ async def refresh(
226230 user_data = await get_user_by_id_ (user_id , session )
227231
228232 if not user_data :
233+ increment_auth_failure ("user_not_found" , "refresh_token" )
234+ category_logger .warning (
235+ f"Refresh attempted with non-existent user ID: { user_id } " ,
236+ LogCategory .AUTH ,
237+ )
229238 raise HTTPException (
230239 status .HTTP_404_NOT_FOUND , ResponseMessages .USER_NOT_FOUND
231240 )
@@ -273,6 +282,11 @@ async def verify(code: str, session: AsyncSession) -> None:
273282 or len (code ) > MAX_JWT_TOKEN_LENGTH
274283 or not is_valid_jwt_format (code )
275284 ):
285+ increment_auth_failure ("invalid_token" , "verify_email" )
286+ category_logger .warning (
287+ "Email verification with invalid token format" ,
288+ LogCategory .AUTH ,
289+ )
276290 raise HTTPException (
277291 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
278292 )
@@ -320,17 +334,32 @@ async def verify(code: str, session: AsyncSession) -> None:
320334 user_data = await get_user_by_id_ (user_id , session )
321335
322336 if not user_data :
337+ increment_auth_failure ("user_not_found" , "verify_email" )
338+ category_logger .warning (
339+ f"Email verification with non-existent user ID: { user_id } " ,
340+ LogCategory .AUTH ,
341+ )
323342 raise HTTPException (
324343 status .HTTP_404_NOT_FOUND , ResponseMessages .USER_NOT_FOUND
325344 )
326345
327346 # block a banned user
328347 if bool (user_data .banned ):
348+ increment_auth_failure ("banned_user" , "verify_email" )
349+ category_logger .warning (
350+ f"Banned user { user_data .id } attempted email verification" ,
351+ LogCategory .AUTH ,
352+ )
329353 raise HTTPException (
330354 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
331355 )
332356
333357 if bool (user_data .verified ):
358+ increment_auth_failure ("already_verified" , "verify_email" )
359+ category_logger .warning (
360+ f"User { user_data .id } verification when already verified" ,
361+ LogCategory .AUTH ,
362+ )
334363 raise HTTPException (
335364 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
336365 )
@@ -353,13 +382,15 @@ async def verify(code: str, session: AsyncSession) -> None:
353382 )
354383
355384 except jwt .ExpiredSignatureError as exc :
385+ increment_auth_failure ("expired_token" , "verify_email" )
356386 category_logger .warning (
357387 "Expired verification token used" , LogCategory .AUTH
358388 )
359389 raise HTTPException (
360390 status .HTTP_401_UNAUTHORIZED , ResponseMessages .EXPIRED_TOKEN
361391 ) from exc
362392 except jwt .InvalidTokenError as exc :
393+ increment_auth_failure ("invalid_token" , "verify_email" )
363394 category_logger .warning (
364395 "Invalid verification token used" , LogCategory .AUTH
365396 )
@@ -425,6 +456,11 @@ async def reset_password(
425456 or len (code ) > MAX_JWT_TOKEN_LENGTH
426457 or not is_valid_jwt_format (code )
427458 ):
459+ increment_auth_failure ("invalid_token" , "password_reset" )
460+ category_logger .warning (
461+ "Password reset with invalid token format" ,
462+ LogCategory .AUTH ,
463+ )
428464 raise HTTPException (
429465 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
430466 )
@@ -472,12 +508,22 @@ async def reset_password(
472508 user_data = await get_user_by_id_ (user_id , session )
473509
474510 if not user_data :
511+ increment_auth_failure ("user_not_found" , "password_reset" )
512+ category_logger .warning (
513+ f"Password reset with non-existent user ID: { user_id } " ,
514+ LogCategory .AUTH ,
515+ )
475516 raise HTTPException (
476517 status .HTTP_404_NOT_FOUND , ResponseMessages .USER_NOT_FOUND
477518 )
478519
479520 # Block banned users from resetting password
480521 if bool (user_data .banned ):
522+ increment_auth_failure ("banned_user" , "password_reset" )
523+ category_logger .warning (
524+ f"Banned user { user_data .id } attempted password reset" ,
525+ LogCategory .AUTH ,
526+ )
481527 raise HTTPException (
482528 status .HTTP_401_UNAUTHORIZED , ResponseMessages .INVALID_TOKEN
483529 )
@@ -499,13 +545,15 @@ async def reset_password(
499545 )
500546
501547 except jwt .ExpiredSignatureError as exc :
548+ increment_auth_failure ("expired_token" , "password_reset" )
502549 category_logger .warning (
503550 "Expired password reset token used" , LogCategory .AUTH
504551 )
505552 raise HTTPException (
506553 status .HTTP_401_UNAUTHORIZED , ResponseMessages .EXPIRED_TOKEN
507554 ) from exc
508555 except jwt .InvalidTokenError as exc :
556+ increment_auth_failure ("invalid_token" , "password_reset" )
509557 category_logger .warning (
510558 "Invalid password reset token used" , LogCategory .AUTH
511559 )
@@ -636,6 +684,7 @@ async def get_jwt_user( # noqa: C901
636684
637685 # Check user validity - user must exist, be verified, and not banned
638686 if not user_data :
687+ increment_auth_failure ("user_not_found" , "jwt" )
639688 category_logger .warning (
640689 "Authentication attempted with invalid user token" ,
641690 LogCategory .AUTH ,
0 commit comments