Vérification de l’email à la création d’un compte – Reset password – Node.js
Dans cet article je détaille comment mettre en place la vérification de la validité d’un email lors de la création d’un compte utilisateur. Notamment l’utilisation de json web token et les routes à utiliser / créer côté serveur.
Sur le même principe, je détaille également le flow du reset du mot de passe de l’utilisateur. En plus d’être à durée limitée le lien fourni sera à usage unique.
Dans les deux cas, il y a envoi d’un email à l’adresse renseignée par l’utilisateur, j’ai utilisé nodemailer dont je ne détaillerai pas l’utilisation.
Egalement, je ne détaille pas ici la mise en place d’un serveur avec Node.js et les extraits de code fournis sont pas mal simplifiés. Cependant le code complet de mon application d’authentification est disponible dans son repo github.
Ressources :
- Un tuto sur Youtube (en anglais)
- Nodemailer,
- json web token,
- Le repo github de l’app d’authentification contenant une implémentation de la validation de l’email et du reset password.
Le principe général, les étapes
Validation de l’email
- L’utilisateur (ou client) POST un formulaire de signup,
- Si le formulaire est validé par le serveur :
- il (le serveur) créé un nouveau compte en base de données avec une prop « active » à « false », évidemment le login sera conditionné à cette prop,
- il créé un token de vérification valable 15mn en utilisant l’id retourné par la base et l’email fourni,
- il envoi un lien contenant le token à l’adresse mail fournie dans le formulaire de signup.
- Finalement, il renvoie également au client l’info d’aller checker ses mails pour suivre le lien fourni afin de valider son adresse mail.
- L’utilisateur clique le lien fourni,
- Le serveur reçoit et décode les infos contenues dans le token du lien et après validation passe la prop « active » du compte à « true »,
- Après au choix : login ou info que l’utilisateur peut se logguer.
Reset du mot de passe en cas de perte
L’utilisateur (ou client) POST un formulaire de reset du mot de passe (son email quoi).
Si la demande est validée par le serveur (l’email existe en base de données) :
- Il (le serveur) fabrique un lien avec l’id de l’utilisateur et un token créé partiellement à partir de son mot de passe,
- Il envoi le mail à l’adresse fournie et l’info à l’utilisateur de checker ses mails,
L’utilisateur valide le lien reçu et fait ainsi une requête GET vers une route dédiée du serveur.
Si elle est validée, le serveur fait suivre la requête vers une page contenant un formulaire de saisie d’un nouveau mot de passe.
Le serveur réceptionne le formulaire sur une route POST dédiée et après validation modifie le mot de passe en base de donnée.
Validation de l’email en détail
POST /signup côté serveur
Donc le serveur réceptionne un formulaire contenant les données utilisateur sur sa route POST /signup.
Les données valides récupérées sont du type :
Avec ça on fait les vérifications d’usage et si tout passe on peut insérer un nouvel utilisateur en base de données.
Création du compte en base de données, active: false
Parmis les props associées à l’utilisateur (pseudo, password, email…) il faudra ajouter une prop « active » initialisée à « false » tant que l’email n’est pas validé. Le login quand à lui ne sera possible que si la prop « active » de l’utilisateur qui tente de se logguer vaut « true ».
Il est nécessaire de créer un compte en base de données afin d’avoir un identifiant pour l’utilisateur. Cet identifiant fera partie du payload codé dans le token envoyé pour validation de l’adresse mail.
Fabrication d’un lien de validation et envoi
Bien, le formulaire de signup est validé, un nouvel utilisateur est créé en base de données avec une prop « active: false », il ne peut pas encore se logguer.
Il est temps de fabriquer puis envoyer un lien de confirmation à l’adresse mail fournie.
Quelques lignes de code pour illustrer ça, le code est bien sûr à adapter :
On commence par créer un token à partir du JWT_SECRET (la chaine de caractère secrète stockée dans votre fichier .env), de l’email, du mot de passe et de l’identifiant de l’utilisateur. Validité 15 minutes.
On créé et on envoi le lien à l’utilisateur, BASE_URL étant l’url de l’application.
Si tout se passe selon le plan, l’utilisateur reçoit le mail contenant le lien envoyé et il clique dessus. Notre serveur récupère la requête sur la route dédiée.
Route nécessaire à la récupération du lien verify-email:
Un controller vérifie le token reçu :
- On récupère le payload contenant id, email et password,
- On récupère l’utilisateur correspondant à l’id,
- On compare les emails du token et de l’utilisateur récupéré,
- Si les emails correspondent, on passe la prop « active » à « true » pour le compte utilisateur correspondant,
- Ici next() renvoie au middleware de login permettant de logguer l’utilisateur directement, les informations nécessaires étant disponibles via le payload du token (email, password).
Et c’est bon pour la validation de l’email avec un login dans la foulée !
Le reset du mot de passe en détail
POST /forgot-pwd côté serveur
Ici l’utilisateur a saisi son email dans le formulaire « Mot de passe oublié » du front, il est réceptionné par le serveur et envoyé au controller.
Si les contrôles sont ok, (essentiellement un compte correspondant à l’email fourni existe en base de données) un lien de reset du mot de passe est envoyé à l’adresse mail fournie.
Création d’un lien avec token et envoi mail à l’utilisateur
- Vérification de l’existence du mail en base de données,
- Récupération des données utilisateur correspondantes,
- Création du token en utilisant comme clé secrète une combinaison JWT_SECRET + password, cela permet d’avoir une clé de décodage valable uniquement tant que le mot de passe n’a pas été changé.
- On fabrique le lien, lorsque l’utilisateur le suivra il sera dirigé vers le formulaire de saisie de son nouveau mot de passe.
Route de retour du lien reset-pwd envoyé par mail
A ce point, l’utilisateur a cliqué sur le lien reçu pour le reset de son mot de passe, le serveur réceptionne la requête GET et la passe au controller :
- Vérification que l’utilisateur existe,
- Reconstitution de la clé de codage unique, valable tant que le mot de passe n’est pas modifié en base de données,
- Décodage du token et renvoi de la vue contenant le formulaire de saisie du nouveau mot de passe.
On renvoi une vue contenant un formulaire du type :
La validation du formulaire avec le nouveau mot de passe renvoi à la même url mais en méthode POST, ainsi l’identifiant et le token sont conservés.
Route pour réception, validation et update du nouveau mot de passe
Ici on reçoit donc un identifiant, un token formé avec le JWT_SECRET et l’ancien mot de passe de l’utilisateur (toujours en base de données) et un formulaire avec le nouveau mot de passe.
On passe tout ça au controlleur, si le formulaire est validé, on récupère l’utilisateur et on peut enfin modifier son mot de passe :
A partir du moment ou le mot de passe est modifié en base de données le lien pour le reset envoyé précedemment par mail à l’utilisateur n’est plus valable. S’il est à nouveau suivi, le serveur renverra ce qui est prévu dans le bloc catch du controlleur « getResetPwd ».
Et voilà ! pour le reset du mot de passe.