Search code examples
phplaravelemaillocalhostemail-verification

Laravel Email verification link using localhost in a production


I've been dealing with an issue for a long time and haven't found a solution. I'm using Laravel 9 in production, and when the user registers, the verification email is automatically sent, but upon arrival, the following address is seen:

http://localhost/verify-email/3322/45a667c298ca4ffd2d8f3ea002d9a11c4391ff63?expires=1710354098&signature=1ffba796dc8f5368a064f735fce8888f11b9cfd1ca630444283ab11039a8bc00

The automatic sending (the first time) is sent with LOCALHOST, but when the user manually clicks the resend button, it sends CORRECTLY.

I'm not using or configured queues. How can I fix this problem?

I've already tried: php artisan optimize:clear

This is my .env configuration.

APP_NAME=somefun
APP_ENV=production
APP_KEY=base64:YUiSMZfKLyWPixk3guHIeYS259kX3FD6Yn82osjIIHI=
APP_DEBUG=false
APP_URL=http://somefun.com.mx

I can't find a way to publish the verification email file (Illuminate/Auth/Notifications/VerifyEmail.php), to change de link generation. Because there isn't on vendor publish.

Please help.


Solution

  • When the notification is sent the first time it does not take it from .env, but rather interprets it from the incoming request to solve it I had to do the following:

    1. Create a new notification: php artisan make:notification VerifyEmail

    2. Make it extend the original in Illuminate\Auth\Notifications\VerifyEmail

    3. Overwrite the parent function that creates the url verificationUrl with a copy of it but including a new line:

    It stays like this:

    <?php
    
    namespace App\Notifications;
    
    use Illuminate\Support\Carbon;
    use Illuminate\Support\Facades\URL;
    use Illuminate\Support\Facades\Config;
    use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailNotification;
    
    class VerifyEmail extends VerifyEmailNotification
    {
    
        /**
         * Get the verification URL for the given notifiable.
         *
         * @param  mixed  $notifiable
         * @return string
         */
        protected function verificationUrl($notifiable)
        {
            if (static::$createUrlCallback) {
                return call_user_func(static::$createUrlCallback, $notifiable);
            }
    
            URL::forceRootUrl(config('app.url')); //<-------THIS FIXED
    
            return URL::temporarySignedRoute(
                'verification.verify',
                Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
                [
                    'id' => $notifiable->getKey(),
                    'hash' => sha1($notifiable->getEmailForVerification()),
                ]
            );
        }
    }
    
    
    1. In app\Models\User.php overwrite the trait function by passing it a new instance of the new notification:
    <?php
    
    namespace App\Models;
    
    use Exception;
    use Stripe\Account;
    use Stripe\StripeClient;
    use Laravel\Cashier\Billable;
    use Laravel\Sanctum\HasApiTokens;
    use App\Notifications\VerifyEmail; //<-------Reference to new notification
    use Spatie\Permission\Traits\HasRoles;
    use Illuminate\Notifications\Notifiable;
    use Illuminate\Contracts\Auth\MustVerifyEmail;
    use Illuminate\Foundation\Auth\User as Authenticatable;
    
    class User extends Authenticatable implements MustVerifyEmail
    {
        use HasApiTokens,  Notifiable, HasRoles, Billable;
    
        protected $guarded = [];
    
        //>>>>Overwrite the trait function by passing it a new instance of the new notification<<<<<<<
        public function sendEmailVerificationNotification()
        {
            $this->notify(new VerifyEmail);
        }
    }
    

    Forcing the url, I don't know if it's a good idea, because I've read that it can do some strange things, but for now I'm not experiencing any inappropriate behavior.