Lintume
3 min readAug 20, 2022

--

Laravel signed routes.

Starting with version 5.6.12, Laravel has acquired the useful functionality of “signing” routes. Since I decided on cryptography, I decided to thoroughly deal with this feature and tell you how to use it.

Let’s see what the official documentation says:
“Laravel allows you to easily create “signed” URLs to named routes. These URLs have a “signature” hash appended to the query string which allows Laravel to verify that the URL has not been modified since it was created. Signed URLs are especially useful for routes that are publicly accessible yet need a layer of protection against URL manipulation.”

So, the article consists of such parts:

  • What for?
  • How to use it?
  • How does it work?

Examples of using:

  1. You need to send a letter to the user with a simple question and answer yes/no. For example, if he will go to an event. If the user is not authorized on the site — he has to log in, and probably — he will not do this and you will remain unanswered;
  2. You need to confirm the user’s mailbox. The same task — it is necessary to confirm the data without authorization.

Here we come to the aid of signed routes. The user does not have to log in to follow the link, but the link can reliably identify the information transmitted, namely that it has not been changed.
By the way, in Laravel 5.7, on the basis of the subscribed routes, the built-in functionality for confirming the user’s email box appeared.

Let us consider in practice the second case. We need, for example, to confirm a user’s mailbox change by sending him a letter to a new mailbox with a confirming link.

Make sure that you have a middleware “signed” in Http / Kernel.php:

protected $routeMiddleware = [
‘signed’ => \Illuminate\Routing\Middleware\ValidateSignature::class,
];

Create such a route.

use Illuminate\Http\Request;Route::get(‘email/{email}/{user}’, function ($email, $user) {
if (! $request->hasValidSignature()) {
abort(401);
}
// Action
})->name(‘changeEmail’)->middleware(‘signed’);

In this case, just we need information about the new email and user id to enter data about the modified mailbox in the database. There can be any route and parameters. The main thing is to add on it the middleware “signed” and the name.

To access our route we generate a link with the data:

use \Illuminate\Support\Facades\URL;$url = URL::temporarySignedRoute(‘changeEmail’, now()->addHour(), [‘email’ => ‘test@test.com’,‘user’ => 1]);

This link we will put in the letter with the request for confirmation of the box. In this case, we created a temporary link (1 hour) using temporarySignedRoute.

Laravel generates a link of the form:

http://test.local/email/test@test.com/1?expires=1563484975&signature=7d9327deebf6d5d692e2574da4b7389f7e91833024696aaf4a8bbbc0ae2b0721

Now, using this link, if any data in it changes (user id, or some character from the signature, email) Laravel throws an exception Illuminate\Routing\Exceptions\InvalidSignatureException. This protects the application from brute force and data integrity.

If there is no need to limit the duration of the link, then just use signedRoute.

$url = URL::signedRoute(‘changeEmail’, [‘email’ => ‘test@test.com’,‘user’ => 1]);

And now the section for the most curious or interested in crypto component question.
Actually, the most visual function of this whole system is \Illuminate\Routing\UrlGenerator::signedRoute.

What is the signature?
This is the HMAC hash (sha256) from the route itself (in our case it is “http: //test.local/email/test@test.com/1” + the expiration parameter of the link “?expires = 1563484975” in UNIX timestamp format).
The encryption key is the application’s secret key, which we generate while creating an application with the key:generate command and which is registered in .env.
Verification of the signature is taken again from the reference (http: //test.local/email/test@test.com/1?expires = 1563484975) of the HMAC hash and its verification with the signature.

That’s all the magic!
I hope I was able to communicate clearly how to use the signed routes and how it works :)

Sources:

  1. Getting Started with Signed Routes in Laravel https://laravel-news.com/signed-routes
  2. URL Generation https://laravel.com/docs/5.8/urls#signed-urls
  3. HMAC https://ru.wikipedia.org/wiki/HMAC

--

--