@@ -4,6 +4,7 @@ const jwt = require('jsonwebtoken');
44const User = require ( '../models/User.model' ) ;
55const { sendSuccess } = require ( '../utils/response' ) ;
66const { sendEmail } = require ( '../services/email.service' ) ;
7+ const passwordResetTemplate = require ( '../services/templates/passwordReset.template' ) ;
78const emailVerificationTemplate = require ( '../services/templates/emailVerification.template' ) ;
89
910/**
@@ -271,10 +272,61 @@ const resetPassword = async (req, res, next) => {
271272 }
272273} ;
273274
275+ /**
276+ * Request a password reset email
277+ * POST /api/auth/forgot-password
278+ */
279+ const forgotPassword = async ( req , res , next ) => {
280+ try {
281+ const { email } = req . body ;
282+ const genericMessage =
283+ 'If an account with that email exists, a password reset link has been sent.' ;
284+
285+ const user = await User . findOne ( { email : email . toLowerCase ( ) } ) ;
286+
287+ if ( ! user ) {
288+ return sendSuccess ( res , { } , 200 , genericMessage ) ;
289+ }
290+
291+ const resetToken = crypto . randomBytes ( 32 ) . toString ( 'hex' ) ;
292+ const resetTokenHash = crypto . createHash ( 'sha256' ) . update ( resetToken ) . digest ( 'hex' ) ;
293+
294+ user . resetPasswordToken = resetTokenHash ;
295+ user . resetPasswordExpires = new Date ( Date . now ( ) + 60 * 60 * 1000 ) ; // 1 hour
296+ await user . save ( ) ;
297+
298+ const frontendUrl = process . env . FRONTEND_URL || 'http://localhost:3000' ;
299+ const resetLink = `${ frontendUrl } /reset-password?token=${ resetToken } ` ;
300+ const html = passwordResetTemplate ( user . fullName , resetLink , '1 hour' ) ;
301+
302+ try {
303+ await sendEmail ( {
304+ to : user . email ,
305+ subject : 'Password Reset Request' ,
306+ html,
307+ } ) ;
308+ } catch {
309+ user . resetPasswordToken = null ;
310+ user . resetPasswordExpires = null ;
311+ await user . save ( ) ;
312+
313+ const error = new Error ( 'Failed to send password reset email. Please try again later.' ) ;
314+ error . statusCode = 500 ;
315+ error . isOperational = true ;
316+ return next ( error ) ;
317+ }
318+
319+ return sendSuccess ( res , { } , 200 , genericMessage ) ;
320+ } catch ( error ) {
321+ return next ( error ) ;
322+ }
323+ } ;
324+
274325module . exports = {
275326 register,
276327 login,
277328 logout,
278329 resetPassword,
330+ forgotPassword,
279331 verifyEmail,
280332} ;
0 commit comments