DEV Community

Tien Ho
Tien Ho

Posted on

How to Create a Laravel URL Temporary Signed Route to an External URL

In Laravel, signed URLs are a powerful way to ensure the integrity of routes by adding a signature that validates the URL. However, Laravel’s native signed routes feature is generally used for internal routes. What if you want to create a temporary signed route that redirects to an external URL? This article will guide you through the process.

Understand Laravel's Signed Routes

Laravel's signed URLs are typically used to generate links that point to a specific route within your application. These URLs carry a unique signature, which Laravel can validate to ensure that the URL has not been tampered with.

use Illuminate\Support\Facades\URL;

URL::temporarySignedRoute('name.route', now()->addMinutes(30), ['parameter' => $value]);

Enter fullscreen mode Exit fullscreen mode

The code snippet above generates a URL that is valid for 30 minutes and includes a signature that ensures its validity.

Create a Signed Route for an External URL

This class is derived from the Illuminate\Routing\UrlGenerator.

<?php

namespace App\Helpers;


use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;

use Illuminate\Support\InteractsWithTime;
use Illuminate\Support\Arr;
class CustomSignedUrl
{
    use InteractsWithTime;
    public function customSignedUrl($baseUrl, $parameters = [], $expiration = null, $absolute = true)
    {
        $this->ensureSignedRouteParametersAreNotReserved(
            $parameters = Arr::wrap($parameters)
        );

        if ($expiration) {
            $parameters = $parameters + ['expires' => $this->availableAt($expiration)];
        }

        ksort($parameters);

        $key = env("APP_FRONT_KEY");

        $rt =  $baseUrl ."?expires={$parameters['expires']}";
        $parameters['signature'] =  hash_hmac('sha256', $rt, $key);
        return $baseUrl ."?expires={$parameters['expires']}&signature={$parameters['signature']}";
    }

    /**
     * Ensure the given signed route parameters are not reserved.
     *
     * @param  mixed  $parameters
     * @return void
     */
    protected function ensureSignedRouteParametersAreNotReserved($parameters)
    {
        if (array_key_exists('signature', $parameters)) {
            throw new \Exception(
                '"Signature" is a reserved parameter when generating signed routes. Please rename your route parameter.'
            );
        }

        if (array_key_exists('expires', $parameters)) {
            throw new \Exception(
                '"Expires" is a reserved parameter when generating signed routes. Please rename your route parameter.'
            );
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Use the Signed External URL

Assume we have two domains: one for the admin side and one for the front page. We want to create a front page user from the admin side and send an email verification.

This's code for custom send verify email.

 <?php

namespace App\Mail;

use App\Helpers\CustomSignedUrl;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\InteractsWithTime;
class CustomVerifyEmail extends VerifyEmail
{
    use InteractsWithTime;
    protected function verificationUrl($notifiable)
    {
        if (static::$createUrlCallback) {
            return call_user_func(static::$createUrlCallback, $notifiable);
        }

        $sha1 = sha1($notifiable->email);
        $id = $notifiable->getKey();
        $baseUrl = env('APP_FRONT_URL')."app/verify-email/{$id}/{$sha1}";

        $signedUrl = (new CustomSignedUrl())->customSignedUrl($baseUrl, [
                'id' => $id,
                'hash' => $sha1
            ],
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60))
        );

        return $signedUrl;

    }
}

Enter fullscreen mode Exit fullscreen mode

Front User model:

...
    public function sendEmailVerificationNotification()
    {
        $this->notify(new CustomVerifyEmail);
    }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)