> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Réinitialisation du mot de passe

> Comment implémenter la réinitialisation du mot de passe dans Laravel.

## Introduction

La réinitialisation du mot de passe est un flux d'authentification indispensable. Les kits de démarrage la construisent automatiquement, mais pour un projet API uniquement ou une UI personnalisée, il faut l'implémenter manuellement.

**Quand implémenter manuellement :**

* Backend d'API seulement (frontend SPA ou application mobile)
* Construction d'une UI d'authentification sans kit de démarrage
* Personnalisation complète des e-mails et de l'URL de réinitialisation

<Info>
  Si vous avez créé votre projet avec un kit de démarrage (`laravel new`), la réinitialisation du mot de passe est déjà en place. Cette page explique l'implémentation sans kit.
</Info>

Vue d'ensemble du flux :

```mermaid theme={null}
flowchart TD
    A["Utilisateur"] --> B["Saisie de l'e-mail<br>GET /forgot-password"]
    B --> C["Envoi du lien<br>POST /forgot-password"]
    C --> D["Réception de l'e-mail<br>URL avec token"]
    D --> E["Formulaire de reset<br>GET /reset-password/{token}"]
    E --> F["Changement du mot de passe<br>POST /reset-password"]
    F --> G["Redirection vers<br>la page de connexion"]
```

## Configuration

La configuration se fait dans `config/auth.php` sous la clé `passwords`.

```php theme={null}
// config/auth.php

'passwords' => [
    'users' => [
        'driver' => 'database',
        'provider' => 'users',
        'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
        'expire' => 60,
        'throttle' => 60,
    ],
],
```

* `driver` — mode de stockage (`database` ou `cache`)
* `expire` — durée de validité du token en minutes (60 par défaut)
* `throttle` — délai (secondes) avant qu'un nouveau lien puisse être demandé

## Drivers

### Driver `database`

Driver par défaut. Il stocke les tokens dans la table `password_reset_tokens`. Cette table fait partie de la migration par défaut (`0001_01_01_000000_create_users_table.php`).

```php theme={null}
'passwords' => [
    'users' => [
        'driver' => 'database',
        'provider' => 'users',
        'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
        'expire' => 60,
        'throttle' => 60,
    ],
],
```

### Driver `cache`

<Tip>
  Option nouvelle disponible depuis Laravel 11. Elle ne nécessite pas de table dédiée, ce qui simplifie la configuration.
</Tip>

Le driver `cache` stocke les tokens dans le cache. Aucune migration de table n'est requise. Comme la clé de cache est l'e-mail de l'utilisateur, veillez à ne pas réutiliser cette clé ailleurs dans l'application.

```php theme={null}
'passwords' => [
    'users' => [
        'driver' => 'cache',
        'provider' => 'users',
        'store' => 'passwords', // Optionnel : store de cache dédié
        'expire' => 60,
        'throttle' => 60,
    ],
],
```

Spécifier un `store` dédié évite que `php artisan cache:clear` n'efface les données de reset. La valeur doit correspondre à un store défini dans `config/cache.php`.

## Préparation du modèle

Deux traits sont nécessaires sur `App\Models\User`.

```php theme={null}
<?php

namespace App\Models;

use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable, CanResetPassword;

    // ...
}
```

* `Notifiable` — nécessaire pour envoyer des notifications par e-mail
* `CanResetPassword` — fournit les méthodes de génération et de vérification des tokens

<Info>
  Le modèle `User` par défaut inclut déjà ces traits. Aucune action supplémentaire n'est requise sur une installation neuve.
</Info>

## Implémentation du routage

Quatre routes sont nécessaires.

### 1. Formulaire de demande de lien

Formulaire pour saisir l'e-mail.

```php theme={null}
// routes/web.php

Route::get('/forgot-password', function () {
    return view('auth.forgot-password');
})->middleware('guest')->name('password.request');
```

Vue Blade correspondante :

```blade theme={null}
{{-- resources/views/auth/forgot-password.blade.php --}}

<form method="POST" action="/forgot-password">
    @csrf

    <div>
        <label for="email">Adresse e-mail</label>
        <input id="email" type="email" name="email" value="{{ old('email') }}" required autofocus>
        @error('email')
            <span>{{ $message }}</span>
        @enderror
    </div>

    @if (session('status'))
        <div>{{ session('status') }}</div>
    @endif

    <button type="submit">Envoyer le lien de réinitialisation</button>
</form>
```

### 2. Traitement de l'envoi du lien

Reçoit le formulaire et envoie l'e-mail via `Password::sendResetLink()`.

```php theme={null}
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

Route::post('/forgot-password', function (Request $request) {
    $request->validate(['email' => 'required|email']);

    $status = Password::sendResetLink(
        $request->only('email')
    );

    return $status === Password::ResetLinkSent
        ? back()->with(['status' => __($status)])
        : back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');
```

`Password::sendResetLink()` retourne une constante de statut.

| Constante                   | Description                       |
| --------------------------- | --------------------------------- |
| `Password::ResetLinkSent`   | Lien envoyé                       |
| `Password::INVALID_USER`    | Aucun utilisateur pour cet e-mail |
| `Password::RESET_THROTTLED` | Envoi limité (throttling)         |

### 3. Formulaire de réinitialisation

Affiche le formulaire pour saisir un nouveau mot de passe lorsque l'utilisateur clique sur le lien.

```php theme={null}
Route::get('/reset-password/{token}', function (string $token) {
    return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');
```

Vue correspondante :

```blade theme={null}
{{-- resources/views/auth/reset-password.blade.php --}}

<form method="POST" action="/reset-password">
    @csrf

    <input type="hidden" name="token" value="{{ $token }}">

    <div>
        <label for="email">Adresse e-mail</label>
        <input id="email" type="email" name="email" value="{{ old('email') }}" required autofocus>
        @error('email')
            <span>{{ $message }}</span>
        @enderror
    </div>

    <div>
        <label for="password">Nouveau mot de passe</label>
        <input id="password" type="password" name="password" required>
        @error('password')
            <span>{{ $message }}</span>
        @enderror
    </div>

    <div>
        <label for="password_confirmation">Confirmation du mot de passe</label>
        <input id="password_confirmation" type="password" name="password_confirmation" required>
    </div>

    <button type="submit">Réinitialiser le mot de passe</button>
</form>
```

### 4. Traitement de la réinitialisation

Reçoit le formulaire et met à jour le mot de passe via `Password::reset()`.

```php theme={null}
use App\Models\User;
use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;

Route::post('/reset-password', function (Request $request) {
    $request->validate([
        'token' => 'required',
        'email' => 'required|email',
        'password' => 'required|min:8|confirmed',
    ]);

    $status = Password::reset(
        $request->only('email', 'password', 'password_confirmation', 'token'),
        function (User $user, string $password) {
            $user->forceFill([
                'password' => Hash::make($password),
            ])->setRememberToken(Str::random(60));

            $user->save();

            event(new PasswordReset($user));
        }
    );

    return $status === Password::PasswordReset
        ? redirect()->route('login')->with('status', __($status))
        : back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');
```

Constantes de statut de `Password::reset()` :

| Constante                 | Description                       |
| ------------------------- | --------------------------------- |
| `Password::PasswordReset` | Réinitialisation réussie          |
| `Password::INVALID_TOKEN` | Token invalide ou expiré          |
| `Password::INVALID_USER`  | Aucun utilisateur pour cet e-mail |

## Durée de validité du token

L'option `expire` de `config/auth.php` définit la durée en minutes (60 par défaut).

```php theme={null}
'passwords' => [
    'users' => [
        'driver' => 'database',
        'expire' => 60, // Expire au bout de 60 minutes
        'throttle' => 60,
    ],
],
```

Avec le driver `database`, les tokens expirés restent en base. Purgez-les régulièrement :

```shell theme={null}
php artisan auth:clear-resets
```

Automatisez via le scheduler.

```php theme={null}
use Illuminate\Support\Facades\Schedule;

Schedule::command('auth:clear-resets')->everyFifteenMinutes();
```

## Personnalisation

### Utiliser une notification personnalisée

Redéfinissez `sendPasswordResetNotification` sur le modèle `User` pour personnaliser l'e-mail.

```php theme={null}
use App\Notifications\ResetPasswordNotification;

class User extends Authenticatable
{
    use Notifiable, CanResetPassword;

    /**
     * Envoie la notification de réinitialisation.
     */
    public function sendPasswordResetNotification($token): void
    {
        $url = 'https://example.com/reset-password?token='.$token;

        $this->notify(new ResetPasswordNotification($url));
    }
}
```

### Personnaliser l'URL du lien

Dans `boot` de `AppServiceProvider`, utilisez `ResetPassword::createUrlUsing()` pour changer l'URL. Utile pour rediriger vers une SPA hébergée sur une autre origine.

```php theme={null}
use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;

public function boot(): void
{
    ResetPassword::createUrlUsing(function (User $user, string $token) {
        return 'https://example.com/reset-password?token='.$token;
    });
}
```

### Configuration des Trusted Hosts

Le lien de réinitialisation est généré à partir de l'en-tête `Host` de la requête HTTP. Pour éviter les requêtes provenant d'hôtes malveillants, configurez les Trusted Hosts dans `bootstrap/app.php`.

```php theme={null}
->withMiddleware(function (Middleware $middleware) {
    $middleware->trustHosts(at: ['example.com']);
})
```

<Warning>
  Vérifiez toujours la configuration Trusted Hosts en implémentant la réinitialisation, sous peine d'être exposé aux attaques par injection d'en-tête Host.
</Warning>

## Récapitulatif

| Objectif                      | Méthode                                        |
| ----------------------------- | ---------------------------------------------- |
| Envoyer un lien               | `Password::sendResetLink(['email' => $email])` |
| Réinitialiser le mot de passe | `Password::reset($credentials, $callback)`     |
| Réinitialiser sans table      | Configurer le driver `cache`                   |
| Supprimer les tokens expirés  | `php artisan auth:clear-resets`                |
| Personnaliser la notification | Surcharger `sendPasswordResetNotification`     |
| Personnaliser l'URL           | `ResetPassword::createUrlUsing()`              |

## Prochaines étapes

<Columns cols={2}>
  <Card title="Introduction à l'authentification" icon="lock" href="/fr/authentication">
    Vue d'ensemble du système d'authentification Laravel.
  </Card>

  <Card title="Notifications" icon="bell" href="/fr/notifications">
    Approfondissez la personnalisation des notifications par e-mail.
  </Card>
</Columns>


## Related topics

- [Hachage (Hashing)](/fr/hashing.md)
- [Mise à niveau de Laravel 10 à 11](/fr/blog/upgrade-10-to-11.md)
- [Mises à jour Laravel — avril 2026](/fr/blog/changelog/202604.md)
- [Kits de démarrage](/fr/starter-kits.md)
- [Laravel Fortify et les starter kits](/fr/advanced/fortify.md)
