0
votes

I am building an angular application and want to implement password reset. However, default laravel config doesn't appear to allow one to do this using purely XMLHttpRequest ($http.post) requests and responds with a 302 redirect.

I managed to get postLogin and postRegister to work without issuing redirects by implementing said methods in authController class and returning a json response, doing this overrides the default laravel implementation of said methods. No such luck with postEmail and it appears the method is not hit at all, I just get a 302 response back immediately.

Ideally, other than to check their E-mail, I don't want the user to leave the single page angular application at all. So 1. User posts E-mail to postEmail -> Email with reset link or better 'reset code' is sent to E-mail address -> User then inputs the reset token code into the already open web app or if it can't be done, browse to reset password page opened in new tab.

I tried implementing postEmail method as such:

public function postEmail(Request $request)
            {

                $this->validate($request, ['email' => 'required|email']);

                $response = Password::sendResetLink($request->only('email'), function (Message $message) {
                    $message->subject($this->getEmailSubject());
                });

                switch ($response) {
                    case Password::RESET_LINK_SENT:


                         return response()->json(['msg' => 'A reset link has been sent to your E-mail'], 200);

                    case Password::INVALID_USER:


                         return response()->json(['msg' => 'This E-mail cannot be found in our system'], 200);
                }
            }

Also, where is template for the E-mail with the reset link that laravel sends out ?

2
You need to create a PasswordController to extend the postEmail() method.Jeemusu

2 Answers

2
votes

You can create a PasswordController within the App\Http\Controllers\Auth namespace to extend the password reset methods.

<?php 

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\PasswordBroker;
use Illuminate\Foundation\Auth\ResetsPasswords;

class PasswordController extends Controller 
{
    use ResetsPasswords;

    public function postEmail(Request $request)
    {

    }

}

To overwrite the email templates you can create a reminder.blade.php in the app/views/emails/auth directory, or change the location of the template file in the app/config/auth.php config.

0
votes

while the accepted answer is completelt valid, another solution withouht overriding the original notification class is as follow, ResetPassword provides a static method called createUrlUsing which accepts a Closure, So we can override the URL as something like below:

use Illuminate\Support\Facades\Password;
use Illuminate\Auth\Notifications\ResetPassword;

...

$status = Password::sendResetLink(
    ['email' => $args['email']],
    function ($user, $token) {
        ResetPassword::createUrlUsing(function ($notifiable, $token) {
            // This is where you override the URL, you can also take a look at 
            // the `url`, `action` and `route` functions in Laravel and skip  
            // `sprintf` if you prefer to stick to Laravel functions only.
            return sprintf(
                "%s/%s/?token=%s&email=%s",
                config('your.optional.frontend_url'),
                config('your.optional.password_reset'),
                $token,
                $notifiable->getEmailForPasswordReset(),
            ); // frontend_url/password_url/?token=TOKEN&email=EMAIL
        });
        return $user->notify(new ResetPassword($token));
    }
);

// This is an optional way to handle the final response, you can convert it to
// JSON or even ignore it.
return $status === Password::RESET_LINK_SENT
    ? ['status' => __($status)]
    : throw new Error(__($status));

This piece of code should be placed at a new route to handle password reset request instead of using default Laravel one.