Skip to content

Refactor auth service and middleware with security improvements - #1

Merged
goncoolio merged 3 commits into
mainfrom
claude/analyse-verification-depot-efjeuf
Aug 7, 2026
Merged

goncoolio merged 3 commits into
mainfrom
claude/analyse-verification-depot-efjeuf

Conversation

@goncoolio

Copy link
Copy Markdown
Owner

Summary

This PR refactors the authentication service and middleware to improve security, error handling, and code maintainability. Key improvements include proper token type validation, account status checks, safer logout handling, and migration of database configuration to environment variables.

Key Changes

Security Improvements

  • Token type validation: Added strict validation in verifyToken() to ensure refresh tokens cannot be used where access tokens are required
  • Account status checks: Added validation in login to prevent blocked/deleted accounts from signing in
  • UUID source validation: Changed changePassword to use UUID from authenticated token instead of request body, preventing users from targeting other accounts
  • Safer logout: Made Authorization header optional on logout endpoint and added null checks to prevent crashes

Authentication Service (authService.js)

  • Improved email sending error handling: registration no longer fails if verification email cannot be sent; user receives alternative message
  • Added null checks in confirmEmailService and confirmTelService to validate user existence and verification code presence
  • Fixed confirmTelService to use correct field names (verification_tel_code instead of verification_email_code)
  • Added missing return statements in sendResetPasswordCodeService and sendMobileResetPasswordCodeService
  • Removed debug console.log statements
  • Changed message variable from const to let for conditional updates

Auth Middleware (authMiddleware.js)

  • Refactored protect middleware to use verifyToken() service with proper token type checking
  • Added validation that access tokens are not blacklisted/logged out
  • Improved error handling with early returns to prevent double response sends
  • Enhanced verifyRefreshToken to validate token type and blacklist status
  • Added automatic cleanup of expired refresh tokens

Token Service (tokenService.js)

  • Changed verifyToken() to throw errors instead of returning error objects for better async/await handling
  • Added token type validation to prevent token type confusion attacks
  • Fixed payload validation to check uuid field (was checking non-existent user_uuid)
  • Fixed saveToken() to use user_uuid instead of user_id

Configuration Management

  • Migrated from JSON to environment variables: Replaced src/config/config.json with src/config/config.js that reads from .env
  • Added .sequelizerc to properly configure Sequelize CLI paths
  • Updated .env.example with database configuration variables
  • Database credentials are no longer committed to repository

Database & Models

  • Updated user migration: changed uuid from primary key to unique constraint with UUIDV4 default
  • Fixed nom field to be non-nullable
  • Updated user status constants to match ENUM values: 'active', 'inactive', 'deleted', 'blocked'

Error Handling

  • Enhanced errorMiddleware.js to properly handle response status codes and prevent double responses
  • Improved email validation in sendEmail.js with better error messages
  • Added SMTP configuration validation

API Documentation

  • Updated README with correct API route paths (/auth/user/ prefix)
  • Clarified authentication requirements (Bearer token vs refresh token)
  • Added documentation for new endpoints (confirm-tel, mobile-reset-password)

Code Quality

  • Removed unused imports and dependencies
  • Improved code formatting and consistency
  • Added helpful comments explaining security decisions
  • Made logout controller use asyncHandler for consistent error handling

https://claude.ai/code/session_01VHL2eLC1T5kD31UxYxyxGX

claude added 3 commits August 5, 2026 19:54
Endpoints cassés :
- confirmTelService n'était pas importé dans le contrôleur : /confirm-tel
  répondait systématiquement 502. Le service lisait de plus
  verification_email_code au lieu de verification_tel_code et renseignait
  email_verified_at au lieu de tel_verified_at.
- verifyToken vérifiait payload.user_uuid alors que generateToken signe
  uuid : /refresh-token échouait toujours et délivrait des tokens portant
  un uuid undefined. La fonction lève désormais une erreur explicite et
  contrôle aussi le type du token.
- logout n'était pas encapsulé dans asyncHandler et déréférençait
  req.headers.authorization sans vérification : requête suspendue quand
  l'entête était absente.
- saveToken écrivait dans une colonne user_id inexistante (user_uuid).
- logger n'était pas importé dans tokenService : le catch de
  generateAuthTokens masquait l'erreur réelle par une ReferenceError.
- createUser réassignait une const et getTokenByDetails masquait le helper
  error() par la variable du catch : TypeError dans les deux cas.
- STATUS_ACTIVE valait 1 alors que la colonne est un ENUM
  ('active','inactive','deleted','blocked').

Sécurité :
- protect acceptait un refresh token comme token d'accès et ignorait
  l'indicateur blacklisted. Le type est désormais vérifié et next() est
  appelé hors du try pour ne plus émettre de double réponse.
- change-password ciblait l'uuid fourni dans le body : il provient
  maintenant du token d'accès. Le champ reste accepté mais est ignoré.
- Suppression des console.log qui exposaient tokens, codes de vérification
  et enregistrements utilisateur.
- Les identifiants de base de données ne sont plus committés : config.json
  est remplacé par config.js alimenté par le .env.
- npm audit : 18 vulnérabilités (2 critiques, 11 hautes) ramenées à 3.

Divers :
- Le handler 404 renvoyait un HTTP 200 avec une charge utile « 403 » ;
  errorHandler n'était jamais branché et répondait 200 sur erreur.
- Ajout de .sequelizerc : sequelize-cli ne trouvait ni la configuration ni
  les migrations situées dans src/.
- Migration Users : uuid était déclaré en seconde clé primaire à côté d'un
  id auto-incrémenté (désormais unique + non nul).
- SMTP : port converti en nombre et TLS implicite activé sur le port 465.
- Un échec d'envoi d'email ne fait plus échouer l'inscription.
- Les services renvoyaient undefined sur certains chemins, ce qui faisait
  planter les contrôleurs.
- README : les routes documentées (/api/auth/...) ne correspondaient pas
  aux routes réelles (/auth/user/...).
- .gitignore nettoyé, .idea retiré du suivi, dépendances inutilisées
  supprimées.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHL2eLC1T5kD31UxYxyxGX
Expiration des codes de vérification :
L'expiration s'appuyait sur updatedAt : n'importe quelle mise à jour du
compte (changement de profil, de statut...) repoussait la validité du code
de 5 minutes supplémentaires. Une colonne verification_code_expires_at est
désormais posée à la génération du code et remise à null à sa consommation.
Un code sans date d'expiration est considéré comme expiré, afin que les
comptes créés avant la migration redemandent simplement un code.

La durée de validité est centralisée dans
verificationCodeConstant.EXPIRATION_MINUTES et reprise dans le texte des
emails. La requête utilisateur redondante de confirmEmailService et
confirmTelService, qui n'existait que pour lire updatedAt, est supprimée.

Dépendances :
- nodemailer 6.x -> 9.x et uuid 9.x -> 14.x, ce qui résout les 3
  vulnérabilités restantes. Vérifié par un aller-retour SMTP réel :
  la compilation du template handlebars et l'envoi fonctionnent avec et
  sans identifiants.
- sendEmail n'envoie plus de bloc auth quand SMTP_EMAIL est vide : les
  relais de développement sans authentification refusaient la connexion.

Les 2 alertes restantes concernent uuid imbriqué dans les dépendances de
sequelize 6 ; l'unique remède proposé par npm est une rétrogradation vers
sequelize 3, et l'avis ne porte que sur uuid v3/v5/v6 appelés avec un
argument buf, ce que le projet ne fait pas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHL2eLC1T5kD31UxYxyxGX
Suite de tests (80 tests, 5 fichiers) sur SQLite en mémoire : ni serveur
MySQL ni fichier .env requis. Les emails sont mockés partout sauf dans
tests/email.test.js, qui démarre un vrai serveur SMTP local pour vérifier
que le template handlebars est réellement compilé et remis.

Les tests couvrent en particulier les régressions corrigées sur cette
branche : typage des tokens, blacklist, expiration des codes, ciblage du
compte par le token et non par le corps de la requête, 404 avec le bon
code HTTP, déconnexion sans entête Authorization.

Deux défauts mis au jour par les tests :

- generateToken ne produisait pas de token unique. Le payload ne contenant
  que uuid, iat (à la seconde), exp et type, deux tokens émis dans la même
  seconde pour le même compte étaient identiques au bit près. La rotation
  du refresh token était donc sans effet : le contrôleur détruisait
  l'ancien puis en réémettait un identique, laissant valide un token
  censé être révoqué. Ajout d'un jti unique.

- Le jti porte le JWT à 272 caractères, au-delà des 255 de la colonne
  token. MySQL en mode strict aurait rejeté l'insertion, et l'aurait
  tronquée sinon. La colonne passe à 512 via une migration, et un test
  compare la longueur émise à la largeur déclarée du modèle, car SQLite
  n'applique pas les longueurs de colonne.

uuid revient de 14.x à ^11.1.1 : les versions 13+ ne fournissent plus de
build CommonJS, et require() n'y fonctionne que sur Node >= 20.19 via le
support require(esm). Le projet étant en CommonJS, le runtime Jest levait
une SyntaxError. La 11.1.1 corrige l'avis de sécurité (qui porte sur
< 11.1.1) tout en conservant le build CJS.

Le logger n'installe plus de rotation de fichiers en environnement de
test : cela laissait des descripteurs ouverts et polluait logs/.

CI (.github/workflows/tests.yml) : suite exécutée sur Node 20 et 22, plus
un job vérifiant que les migrations s'appliquent et se déroulent dans les
deux sens. Node 18 est exclu car sqlite3 exige Node >= 20.17.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHL2eLC1T5kD31UxYxyxGX
@goncoolio
goncoolio merged commit 94fcf4c into main Aug 7, 2026
4 checks passed
@goncoolio
goncoolio deleted the claude/analyse-verification-depot-efjeuf branch August 17, 2026 00:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants