Signed URLs with Laravel

Antoine Lamé
2 min readOct 13, 2021

--

Laravel Signed URLs are great to protect some of your routes by requiring a secret token passed to the URL as a parameter.

This is particularly useful for “unsubscribe” links sent by email to your users, or any other action. This way, your customers don’t need to authenticate themselves in your application to perform the action.

It becomes impossible to unsubscribe the user #23 without the token. It also makes it impossible to unsubscribe a user other than #23, as the hash is linked to the other parameters of the route.

To create a signed URL, you need a named route and use the signedRoute method of the URL facade.

use Illuminate\Support\Facades\URL;

return URL::signedRoute('unsubscribe', ['user' => 23]);

The method returns a string like this: https://foo.test/users/23/unsubcribe?signature=f834ed8570e05de6c50ad10bd6abcf71e9867fcb14bdf2670b4bf572ce346f3b

Set a time limit

You can also set an expiration date when you generate the token. This is useful, for example, if you want to generate a download link that should only be valid for a few minutes.

use Illuminate\Support\Facades\URL;

return URL::temporarySignedRoute(
'files.download', now()->addMinutes(30), ['file' => 6]
);

Verify an incoming request

Now that you know how to generate a signed URL, let’s see how to validate incoming requests.

Option 1 - With the middleware

Just use the signed middleware.

Route::post('users/{user}/unsubscribe', UnsubscribeUser::class)
->name('unsubscribe')
->middleware('signed');

To do this, make sure that the signed middleware is present in the $routeMiddleware property of your App\Http\Kernel class.

use Illuminate\Routing\Middleware\ValidateSignature;

protected $routeMiddleware = [
// ...
'signed' => ValidateSignature::class,
];

Option 2 - With the request method

Alternatively, you can call the hasValidSignature method on the incoming Request:

use Illuminate\Http\Request;

public function unsubscribe(Request $request)
{
if (! $request->hasValidSignature()) {
abort(403);
}

// ...
}

It’s as simple as that!

I hope you enjoyed this post. Feel free to clap this article (👏) and subscribe to my Medium newsletter for more.

👋 I offer tech consulting services for companies that need help with their Laravel applications. I can assist with upgrades, refactoring, testing, new features, or building new apps. Feel free to contact me through LinkedIn, or you can find my email on my GitHub profile.

--

--