L’authentification par lien magique est un processus où un utilisateur se connecte sans mot de passe. Il saisit simplement son adresse e-mail dans un formulaire de connexion. Ensuite, il reçoit un e-mail contenant un lien unique et sécurisé. En cliquant sur ce lien, il est automatiquement authentifié et redirigé vers l’application ou le site. Cette méthode améliore la sécurité en évitant l’usage de mots de passe vulnérables.

1. Créer le lien de connexion

Nous allons utiliser les liens temporaires de Laravel. Cela nous permettra d’invalider le lien au bout d’un certain temps.

final class SendLoginLink
{
	public function handle(string $email): void
	{
		Mail::to(
			users: $email,
		)->send(
			mailable: new LoginLink(
				url: URL::temporarySignedRoute(
					name: 'login:store',
					parameters: [
						'email' => $email,
					],
					expiration: 3600,
				),
			)
		);
	}
}

Il nous suffira juste d’appeler la méthode handle avec l’adresse à laquelle on doit envoyer le mail.

2. Créer le mail avec le lien

Pour se faire nous allons commencer par créer le template Markdown ou Blade de notre mail.

Nous utilisons la commande make de Laravel pour créer notre email en Markdown:

php artisan make:mail LoginLink --markdown=emails.auth.login-link

On peut par la suite, personnalisé notre mail dans le fichier template/emails/auth/login-link.blade.php:

<x-mail::message>
# Connexion 
 
Utilisez le bouton ci-dessous pour vous connecter à {{ config('app.name') }}. 
 
<x-mail::button :url="$url">
	Se connecter
</x-mail::button> 
 
*Si le bouton ne marche pas, vous pouvez copier coller le lien suivant dans votre navigateur*: {{$url}}
 
Merci,<br>
 
{{ config('app.name') }}
</x-mail::message>

On va par la suite modifier notre classe créant le mail.

final class LoginLink extends Mailable
{
	use Queueable, SerializesModels; 
 
	public function __construct(
		public readonly string $url,
	) {} 
 
	public function envelope(): Envelope
	{
		return new Envelope(
			subject: 'Votre lien de connexion',
		);
	} 
 
	public function content(): Content
	{
		return new Content(
			markdown: 'emails.auth.login-link',
			with: [
				'url' => $this->url,
			],
		);
	} 
 
	public function attachments(): array
	{
		return [];
	}
}

3. Authentifier l’utilisateur

On commence par déclarer notre route dans notre fichier routes/web.php:

Route::get('login/{email}', LoginController::class)->middleware('signed')->name('login:store');

On créer notre controller où l’on valide la signature et on authentifie l’utilisateur.

final class LoginController
{
	public function __invoke(Request $request, string $email): RedirectResponse
	{
		if ($request->hasValidSignature() === false) {
			abort(Response::HTTP_UNAUTHORIZED);
		}
 
		$user = User::query()->where('email', $email)->firstOrFail();
 
		Auth::login($user, $remember = true);
 
		return new RedirectResponse(
			url: route('welcome')
		);
	}
}