php - Laravel 403 THIS ACTION IS UNAUTHORIZED. when email verifying

I looked up in Laravel/8.x docs and setup routes for email verification. Here are the routes:

Route::get('/email/verify', function () {
    return view('auth.verify-email');
})->middleware('auth')->name('verification.notice');
Route::get('/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
    $request->fulfill();

    return redirect('/home');
})->middleware(['auth', 'signed'])->name('verification.verify');
Route::post('/email/verification-notification', function (Request $request) {
    $request->user()->sendEmailVerificationNotification();

    return back()->with('message', 'Verification link sent!');
})->middleware(['auth', 'throttle:6,1'])->name('verification.send');

When i click on this <a href="{{ route('verification.verify', ['id' => \Illuminate\Support\Facades\Auth::id(), 'hash' => \Illuminate\Support\Facades\Auth::user()->password]) }}" class="text-sm text-gray-700 underline">Verify email</a> It gives me this error: 403 INVALID SIGNATURE.

EDIT:

I switched to signedRoute in my a tag and now i get 403 THIS ACTION IS UNAUTHORIZED..

Here is mechanism that leads to verification.verify route:

@if (Route::has('login'))
        <div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
            @auth
            <a href="{{ url('/') }}" class="text-sm text-gray-700 underline">Home</a>
            <a href="{{ URL::signedRoute('verification.verify', [
                            'id' =>Auth::id(),
                            'hash' => Auth::user()->password,
                        ])}}" class="text-sm text-gray-700 underline">Verify email</a>
            <a href="{{ route('logout') }}" class="text-sm text-gray-700 underline">Logout</a>
            @else
            <a href="{{ route('login') }}" class="text-sm text-gray-700 underline">Login</a>
            @if (Route::has('register'))
            <a href="{{ route('register') }}" class="ml-4 text-sm text-gray-700 underline">Register</a>
            @endif
            @endauth
        </div>
        @endif

In EmailVerificationRequest i've changed nothing:

under vendor\Laravel\Framework\src\Illuminate\Founndation\Auth\EmailVerificationRequest

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Auth\Events\Verified;
use Illuminate\Foundation\Http\FormRequest;

class EmailVerificationRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        if (! hash_equals((string) $this->route('id'),
                          (string) $this->user()->getKey())) {
            return false;
        }

        if (! hash_equals((string) $this->route('hash'),
                          sha1($this->user()->getEmailForVerification()))) {
            return false;
        }

        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }

    /**
     * Fulfill the email verification request.
     *
     * @return void
     */
    public function fulfill()
    {
        if (! $this->user()->hasVerifiedEmail()) {
            $this->user()->markEmailAsVerified();

            event(new Verified($this->user()));
        }
    }

    /**
     * Configure the validator instance.
     *
     * @param  \Illuminate\Validation\Validator  $validator
     * @return void
     */
    public function withValidator($validator)
    {
        return $validator;
    }
}

Answer

Solution:

You need to use URL::signedRoute to generate signed urls, not the route helper.

URL::signedRoute('verification.verify', [
    'id' => Auth::id(),
    'hash' => Auth::user()->password,
]);

You can read here for more information about signed urls: https://laravel.com/docs/8.x/urls#signed-urls


You are receiving a 403 because you are not passing the parameters that the framework is expecting.

URL::temporarySignedRoute(
    'verification.verify',
    Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
    [
        'id' => Auth::user()->getKey(),
        'hash' => sha1(Auth::user()->getEmailForVerification()),
    ]
);

Source