Vai al contenuto principale

Introduzione

Il reset della password è un flusso di autenticazione fondamentale nelle applicazioni web. Con uno starter kit la funzionalità viene costruita automaticamente, ma nei progetti solo-API o con UI personalizzata serve l’implementazione manuale. Casi in cui serve l’implementazione manuale:
  • Backend solo-API (con frontend SPA o app mobile)
  • Se costruisci autonomamente l’UI di autenticazione senza starter kit
  • Se vuoi personalizzare completamente la notifica email o il design dell’URL di reset
Se hai creato il progetto con uno starter kit (laravel new) il reset password è già implementato. Questa pagina descrive come implementarlo senza starter kit.
Il flusso completo del reset password:

Configurazione

Configura il reset password nella chiave passwords di config/auth.php.
// config/auth.php

'passwords' => [
    'users' => [
        'driver' => 'database',
        'provider' => 'users',
        'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
        'expire' => 60,
        'throttle' => 60,
    ],
],
  • driver — modalità di salvataggio dati (database o cache)
  • expire — validità del token in minuti. Default 60 minuti
  • throttle — tempo di attesa (in secondi) prima di consentire un nuovo invio

Driver

Driver database

È il driver predefinito. Salva il token di reset nella tabella password_reset_tokens del database. Questa tabella è inclusa nelle migration predefinite di Laravel (0001_01_01_000000_create_users_table.php).
'passwords' => [
    'users' => [
        'driver' => 'database',
        'provider' => 'users',
        'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
        'expire' => 60,
        'throttle' => 60,
    ],
],

Driver cache

Nuova opzione disponibile da Laravel 11. Senza tabella nel database implementi il reset con una configurazione minimale.
Il driver cache salva il token nel cache store. Non serve la migration di password_reset_tokens. Il token è indicizzato usando l’email come chiave, quindi assicurati di non usare la stessa email come chiave di cache altrove nell’app.
'passwords' => [
    'users' => [
        'driver' => 'cache',
        'provider' => 'users',
        'store' => 'passwords', // opzionale: store di cache dedicato
        'expire' => 60,
        'throttle' => 60,
    ],
],
Indicando un cache store dedicato nella chiave store eviti che php artisan cache:clear elimini i dati di reset. Il valore deve corrispondere al nome dello store configurato in config/cache.php.

Preparazione del modello

Per usare il reset password, il modello App\Models\User deve avere due trait.
<?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 — necessario per inviare notifiche email
  • CanResetPassword — fornisce i metodi per generare e verificare i token di reset
Il modello User predefinito di Laravel include già questi trait. Nelle nuove installazioni non serve aggiungerli.

Implementazione delle route

Per il reset password servono 4 route. Mostra un form per inserire l’email.
// routes/web.php

Route::get('/forgot-password', function () {
    return view('auth.forgot-password');
})->middleware('guest')->name('password.request');
Vista Blade corrispondente:
{{-- resources/views/auth/forgot-password.blade.php --}}

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

    <div>
        <label for="email">Email</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">Invia link di reset</button>
</form>
Riceve il form e invia l’email con Password::sendResetLink().
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() restituisce una stringa di stato.
Costante di statoDescrizione
Password::ResetLinkSentLink di reset inviato
Password::INVALID_USERNessun utente con quell’email
Password::RESET_THROTTLEDL’invio è limitato (throttling)

3. Form di reset password

Mostra un form per inserire la nuova password quando l’utente clicca il link nell’email.
Route::get('/reset-password/{token}', function (string $token) {
    return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');
Vista Blade corrispondente:
{{-- 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">Email</label>
        <input id="email" type="email" name="email" value="{{ old('email') }}" required autofocus>
        @error('email')
            <span>{{ $message }}</span>
        @enderror
    </div>

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

    <div>
        <label for="password_confirmation">Conferma password</label>
        <input id="password_confirmation" type="password" name="password_confirmation" required>
    </div>

    <button type="submit">Reset password</button>
</form>

4. Elaborazione del reset

Riceve il form e aggiorna la password con Password::reset().
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');
Costanti di stato di Password::reset():
Costante di statoDescrizione
Password::PasswordResetReset password riuscito
Password::INVALID_TOKENToken non valido o scaduto
Password::INVALID_USERNessun utente con quell’email

Scadenza del token

Con l’opzione expire di config/auth.php imposti la validità del token in minuti. Default 60.
'passwords' => [
    'users' => [
        'driver' => 'database',
        'expire' => 60, // scade dopo 60 minuti
        'throttle' => 60,
    ],
],
Con il driver database, i token scaduti restano nel DB. Per pulirli periodicamente usa il comando Artisan:
php artisan auth:clear-resets
Automatizzalo con lo scheduler.
use Illuminate\Support\Facades\Schedule;

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

Personalizzazione

Uso di una notifica personalizzata

Per personalizzare l’email di reset, sovrascrivi il metodo sendPasswordResetNotification sul modello User.
use App\Notifications\ResetPasswordNotification;

class User extends Authenticatable
{
    use Notifiable, CanResetPassword;

    /**
     * Invia la notifica di reset password
     */
    public function sendPasswordResetNotification($token): void
    {
        $url = 'https://example.com/reset-password?token='.$token;

        $this->notify(new ResetPasswordNotification($url));
    }
}
Nel metodo boot di AppServiceProvider, con ResetPassword::createUrlUsing() puoi cambiare l’URL del link di reset. Utile per reindirizzare a un frontend su un’altra origin (SPA).
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;
    });
}

Impostazione dei trusted host

L’URL del link di reset viene generato usando l’header Host della richiesta HTTP. Per prevenire richieste da host non validi, si consiglia di configurare i trusted host in bootstrap/app.php.
->withMiddleware(function (Middleware $middleware) {
    $middleware->trustHosts(at: ['example.com']);
})
Quando implementi il reset password verifica sempre la configurazione dei trusted host. Configurazioni insufficienti espongono al rischio di host header injection.
ObiettivoMetodo
Inviare il link di resetPassword::sendResetLink(['email' => $email])
Reset della passwordPassword::reset($credentials, $callback)
Reset senza tabellaConfigura il driver cache
Eliminare token scadutiphp artisan auth:clear-resets
Personalizzare la notificaSovrascrivere sendPasswordResetNotification
Personalizzare l’URL di resetResetPassword::createUrlUsing()

Prossimi passi

Introduzione all'autenticazione

Impara il funzionamento generale del sistema di autenticazione di Laravel.

Notifiche

Approfondisci la personalizzazione delle notifiche email.
Ultima modifica il 13 luglio 2026