Reset Password without using Email in Laravel

Most web applications provide a way for users to reset their forgotten passwords. Rather than forcing you to re-implement this on each application, Laravel provides convenient methods for sending password reminders and performing password resets.

Laravel’s default for resetting user passwords includes all three fields, i.e email, password and password_confirmation.

Bit of a Background

Here we’ll walk around brief steps on how Laravel Password Reset actually works.

When you setup a new Laravel project and run php artisan migrate for the first time, it ships with default users and password_resets tables. Default routes for password reset include a couple of steps.

Password Recover app.local/recover

/**
*
@param Request $request
*
*
@return JsonResponse
*/
public function
recover( Request $request ) {

$request->validate( [
'email' => 'required|string|email',
] );
$user = User::where( 'email', $request->email )->first();
if ( ! $user ) {
return response()->json( [
'error' => true,
'message' => 'We cannot find a user with that Email Address'
], 404 );
}
$passwordReset = PasswordReset::updateOrCreate(
[ 'email' => $user->email ],
[
'email' => $user->email,
'token' => str_random( 60 )
]
);
if ( $user && $passwordReset ) {
$user->notify(
new PasswordResetRequest( $passwordReset->token )
);
}

return response()->json( [
'error' => false,
'message' => 'We've emailed you your Password reset link.'
] );

}

Password Reset app.local/reset

/**
*
@param Request $request
*
*
@return JsonResponse
*/
public function
reset( Request $request ) {

$request->validate( [
'email' => 'required|string|email',
'password' => 'required|string|confirmed',
'token' => 'required|string'
] );
$passwordReset = PasswordReset::where( [
[ 'token', $request->token ],
[ 'email', $request->email ]
] )->first();
if ( ! $passwordReset ) {
return response()->json( [
'error' => true,
'message' => 'This Password Reset token is invalid.'
], 404 );
}
$user=User::where( 'email', $passwordReset->email )->first();
if ( ! $user ) {
return response()->json( [
'error' => true,
'message' => 'We cannot find a user with that Email Address'
], 404 );
}
$user->password = bcrypt( $request->password );
$user->save();
$passwordReset->delete();
$user->notify( new PasswordResetSuccess( $passwordReset ) );

return response()->json( [
'error' => false,
'message'=>'Your Password changed successfully.'
] );
}

On Password Recover, you’ll receive a email with a token and a temporary record has been created against the email with a temporary token in password_resets table which is to be used for a single time only.

Now if we don’t want to input email on reset page, we can make slight changes to our reset API to take effect.

The Solution

/**
*
@param Request $request
*
*
@return JsonResponse
*/
public function
reset( Request $request ) {

$request->validate( [
'password' => 'required|string|confirmed',
'token' => 'required|string'
] );
$passwordReset = PasswordReset::where( [
[ 'token', $request->token ]
] )->first();
if ( ! $passwordReset ) {
return response()->json( [
'error' => true,
'message' => 'This Password Reset token is invalid.'
], 404 );
}
$userEmail = DB::table( 'password_resets' )->where( 'token', $passwordReset->token )->pluck( 'email' );
$user = User::where( 'email', $userEmail )->first();
if ( ! $user ) {
return response()->json( [
'error' => true,
'message' => 'We cannot find a user with that Email Address'
], 404 );
}
$user->password = bcrypt( $request->password );
$user->save();
$passwordReset->delete();
$user->notify( new PasswordResetSuccess( $passwordReset ) );

return response()->json( [
'error' => false,
'message'=>'Your Password changed successfully.'
] );
}

If you notice, we’re now fetching email based on the request token and rest everything then works exactly the same.

It may not be the perfect solution to this, but seems perfectly fine trick to get the job done in no time.

Try it out & let us know in the comments below.

Learn more about Modifying Password Reset Email Text