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

Corsi's avatar
Level 2

Verifying email through API

Hello everyone,

I am struggling with the signed validation of email validation routes through API. We have a VueJS frontend and a Laravel backend.

When a user registers through the frontend, the backend generates a VerifyEmail notification, which contains a signed route.

We made it so the generated route, which is sent by email to the user, points to our frontend : https://frontend.com/email/verify/xxx/yyyyyy?expires=zzzz&signature=ssssssss

Our front receives that, and thus will call our backend through an API route with the same parameters :

https://backtend.com/api/auth/email/verify/xxx/yyyyyy?expires=zzzz&signature=ssssssss

I used the "absolute/relative" feature so that the domain is not taken into account during validation.

But the problem is that as we are using an API call, my URI is still different than the one sent to the user, as we have a /api/auth prefix.

And so, we calculate a signature on the front URL, but it is then checked against the api URL...

The only idea I have left is to adapt the mechanism behind VerifyEmail to calculate the signature on the API URL, then modify the URL to the frontend version before sending it to the user by email.

It should work, but I feel like butchering everything. Isn't there a built-in feature to deal with such situations ?

1 like
5 replies
vincent15000's avatar

You can effectively exclude the domain from the signed URL.

https://laravel.com/docs/11.x/urls#signed-urls

You may exclude the domain from the signed URL hash by providing the absolute argument to the signedRoute method:

return URL::signedRoute('unsubscribe', ['user' => 1], absolute: false);
Corsi's avatar
Level 2

Thank you Vincent, but I already did that.

My issue is not at domain level but at path level.

Front is /email/verify/..... ==> this is what is signed and sent to the user

Back API is /api/auth/email/verify/.... ==> not the same so the signature validation fails.

So I was wondering if there was any obvious solution I missed, of if this signed URL system is not designed to work with an external front + Laravel back through APIs situation

1 like
Snapey's avatar

make an API endpoint that validates the user (ie just sets the verified_at timestamp)?

1 like
Corsi's avatar
Level 2

@Snapey Thank you, I'll do something like that indeed.

1 like
LaryAI's avatar
Level 58

To handle email verification through an API with a VueJS frontend and a Laravel backend, you can follow these steps to ensure the signed URL verification works correctly:

  1. Customize the Email Verification URL: Modify the VerifyEmail notification to generate a URL that points to your frontend. You can do this by overriding the toMail method in the VerifyEmail notification.

    use Illuminate\Auth\Notifications\VerifyEmail as BaseVerifyEmail;
    use Illuminate\Notifications\Messages\MailMessage;
    
    class VerifyEmail extends BaseVerifyEmail
    {
        public function toMail($notifiable)
        {
            $verificationUrl = $this->verificationUrl($notifiable);
    
            // Modify the URL to point to your frontend
            $frontendUrl = str_replace(
                config('app.url') . '/api/auth/email/verify',
                'https://frontend.com/email/verify',
                $verificationUrl
            );
    
            return (new MailMessage)
                ->subject('Verify Email Address')
                ->line('Click the button below to verify your email address.')
                ->action('Verify Email Address', $frontendUrl);
        }
    }
    
  2. Handle Verification on the Frontend: When the user clicks the verification link, your VueJS frontend should capture the parameters (expires, signature, etc.) and make an API request to your backend.

  3. Create a Custom Verification Route: On your Laravel backend, create a custom route to handle the verification logic. This route should match the parameters from the frontend.

    use Illuminate\Foundation\Auth\EmailVerificationRequest;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Route;
    
    Route::get('/api/auth/email/verify/{id}/{hash}', function (EmailVerificationRequest $request) {
        $request->fulfill();
    
        return response()->json(['message' => 'Email verified successfully.']);
    })->middleware(['signed', 'throttle:6,1'])->name('verification.verify');
    
  4. Ensure URL Signature Validation: The signed middleware will ensure that the URL signature is valid. By using the verification.verify route name, Laravel will automatically handle the signature validation.

  5. Adjust the Verification URL Generation: If needed, you can adjust the URL generation logic to ensure the signature is calculated based on the API route. This can be done by customizing the verificationUrl method in the VerifyEmail notification.

By following these steps, you can ensure that the email verification process works seamlessly between your VueJS frontend and Laravel backend, without having to "butcher" the existing mechanism.

Please or to participate in this conversation.