Using Laravel's Default Password Reset Functionality from an API - Sending the Notification
2 min read

Tags

  • API
  • Laravel
  • Password Reset

This assumes you’ve already setup API authentication in your Laravel application.

I’ve put together the following steps mainly as some sort of future reference, so please pardon the brevity 🙏.

use Illuminate\Contracts\Auth\CanResetPassword;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements CanResetPassword
{
    use HasApiTokens, Notifiable;
    //
}
  • Customize your ResetPasswordController to use the guard of your choice by overriding the guard method on the controller. Since we’re dealing with an API (like in my case), we customize to use the api guard defined in config/auth.php.
namespace App\Http\Controllers\API\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Support\Facades\Auth;

class ResetPasswordController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Password Reset Controller
    |--------------------------------------------------------------------------
    |
    | This controller is responsible for handling password reset requests
    | and uses a simple trait to include this behavior. You're free to
    | explore this trait and override any methods you wish to tweak.
    |
    */

    use ResetsPasswords;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    protected function guard()
    {
        return Auth::guard('api');
    }
}

FYI: Notice my use of namespace App\Http\Controllers\API\Auth; above, I have a custom namespace for all API routes, that is App\Http\Controllers\API, and my authentication controllers are part of this namespace as above.

Also make sure you point your routes to the correct namespaced controllers. Here’s how mine are defined:

Route::group([
    'namespace' => 'Auth',
    'middleware' => 'api',
    'prefix' => 'password'
], function () {
    Route::post('forgot', 'ForgotPasswordController');
    Route::post('reset', 'ResetPasswordController');
});
  • If you’d like to customize the notification email, and more likely the action url in the email sent to the user, then overide the sendPasswordResetNotification method of the CanResetPassword trait as below.
use App\Notifications\PasswordResetRequest;
use Illuminate\Contracts\Auth\CanResetPassword;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements CanResetPassword
{
    use HasApiTokens, Notifiable;
    //

    /**
     * Send the password reset notification.
     *
     * @param  string  $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new PasswordResetRequest($token));
    }
}
  • Update your ForgotPasswordController to look something like this:
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

class ForgotPasswordController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Password Reset Controller
    |--------------------------------------------------------------------------
    |
    | This controller is responsible for handling password reset emails and
    | includes a trait which assists in sending these notifications from
    | your application to your users. Feel free to explore this trait.
    |
    */

    use SendsPasswordResetEmails;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    public function __invoke(Request $request)
    {
        $this->validateEmail($request);
        // We will send the password reset link to this user. Once we have attempted
        // to send the link, we will examine the response then see the message we
        // need to show to the user. Finally, we'll send out a proper response.
        $response = $this->broker()->sendResetLink(
            $request->only('email')
        );
        // return ['received' => true];
        return $response == Password::RESET_LINK_SENT
            ? response()->json(['message' => 'Reset link sent to your email.', 'success' => true], 201)
            : response()->json(['message' => 'Unable to send reset link', 'success' => false], 401);
    }
}

What changes is the use of the __invoke function on the controller, turning it into a single action controller. This change is courtesy of this post by Nasrul Hazim Bin Mohamad.

Now Laravel will take care of sending the reset password link to your users. Will link this to the next article which will detail the steps after the user clicks on the email link.

For any clarifications, questions, or corrections, please post in the comments below.

Happy coding!