Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

LeLand101's avatar

Override email error message on forgot password to success message in Fortify

Hi, using Laravel Fortify, is it possible to change the error message shown in the image to a success message instead? I'm looking to have the link sent to the specified email instead rather than telling the user this email does not exist.

In my Blade view for forgot-password:

<form method="POST" action="{{ route('password.email') }}">
    @csrf
    <div class="mb-3">
        <label for="email" class="form-label">{{ __('Email Address') }}</label>
        <input type="email"
               class="form-control form-control-lg form-control-custom @error('email') is-invalid @enderror"
               id="email" name="email" required/>
        @error('email')
        <span class="invalid-feedback" role="alert">
                <strong>{{ $message }}</strong>
            </span>
        @enderror
    </div>
    <div class="d-grid mx-auto mt-4 mb-4">
        <button class="btn btn-primary btn-lg" type="submit">Reset Password</button>
    </div>
</form>
0 likes
10 replies
LaryAI's avatar
Level 58

Yes, it is possible to override the error message shown on the forgot password form in Laravel Fortify. You can achieve this by customizing the Fortify password reset controller.

Here's how you can do it:

  1. Create a new controller that extends the Fortify password reset controller:
<?php

namespace App\Http\Controllers\Auth;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;

class PasswordResetLinkController extends FortifyPasswordResetLinkController
{
    /**
     * Send a reset link to the given user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse
     */
    public function store(Request $request)
    {
        $request->validate(['email' => 'required|email']);

        $status = Password::sendResetLink(
            $request->only('email')
        );

        if ($status === Password::RESET_LINK_SENT) {
            return back()->with('status', 'A reset link has been sent to your email address.');
        }

        return back()->withErrors(['email' => __($status)]);
    }
}
  1. Update your routes/web.php file to use the new controller:
use App\Http\Controllers\Auth\PasswordResetLinkController;

Route::get('/forgot-password', [PasswordResetLinkController::class, 'create'])
    ->middleware(['guest'])
    ->name('password.request');

Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])
    ->middleware(['guest'])
    ->name('password.email');
  1. Finally, update your Blade view to display the success message:
@if (session('status'))
    <div class="alert alert-success" role="alert">
        {{ session('status') }}
    </div>
@endif

That's it! Now when a user submits the forgot password form, they will see a success message instead of an error message.

LeLand101's avatar

@LaryAI Kept getting incompatible return type for either Responsable or RedirectResponse.

CamKem's avatar

@LeLand101 Are you wanting to send a completely new email, recommending the user to join/create an account? If so, then you will need to create a different controller, one that is not just extending the FortifyPasswordResetLink controller, as that will just send the password reset link, but that will fail as the user does not exist.

LeLand101's avatar

@CamKem No, I'm not looking to send a completely new email. If the email does not exist, I'm looking to have it go forward with a success message instead of informing the user this email does not exist, mainly for security reasons. I read that I can do this by modifying the PasswordResetLinkController but I'm not really sure how to do that. The solution provided by @laryai kept returning incompatible type returns.

CamKem's avatar

@LeLand101 I don't think PasswordResetLinkController is the best place to manage this. I would consider looking at just remove the validation rules from the 'email' section in App/Actions/Fortify/CreateNewUser.php, or if you need more functionality (such as sending the email if validation fails) add your logic.

LeLand101's avatar
LeLand101
OP
Best Answer
Level 1

@CamKem Probably not the best one but I found that this works.

    public function store(Request $request) : Responsable
    {
        $request->validate(['email' => 'required|email']);

        $status = Password::sendResetLink(
            $request->only('email')
        );

        if ($status === Password::RESET_LINK_SENT) {
            return app(SuccessfulPasswordResetLinkRequestResponse::class, ['status' => $status]);
        } else {
            return app(SuccessfulPasswordResetLinkRequestResponse::class, ['status' => "A password reset link has been sent to your email address."]);
        }
    }
CamKem's avatar

@LeLand101 If it works for your purposes it should be fine, I wouldn't worry. Hard to know without getting a larger overview of your project. Good luck with it!

LeLand101's avatar

@CamKem Nah, I'm just looking to not show error message saying email not found when user enters non-existing email to reset their password. But upon testing it, I just changed the message to match with the message for when an actual email was found and link has been sent. Regardless, thanks for the help :D

Snapey's avatar

this should have been all that was required

    public function store(Request $request)
    {
        $request->validate(['email' => 'required|email']);

        $status = Password::sendResetLink(
            $request->only('email')
        );

        return back()->with('status', 'A reset link has been sent to your email address.');
        
    }

This is basically Lary's answer without the if else block at the end

note that the return type is removed from the store method. This has been debated in recent weeks. early Laravel 10 releases had controller stubs that insisted on a specific return type, when most people's controllers have various return types . Taylor backed these out to leave it to those that want strict return types to add their own.

https://laravel-news.com/laravel-10-1-0

LeLand101's avatar

@Snapey Uhm, this still wouldn't work though, the specific error that I keep getting is Return type declaration must be compatible with PasswordResetLinkController->store(request: \Illuminate\Http\Request) : \Illuminate\Contracts\Support\Responsable, hence my workaround with Responsable.

Please or to participate in this conversation.