Cómo adaptar Laravel Fortify para que pueda realizarse la funcionalidad de recordar una clave en un API que usamos desde un frontend separado, activando CORS y redireccionando correctamente a las rutas del frontend.
Antes de empezar, voy a dar un poco de contexto a esta serie de artículos, donde estamos abordando el desarrollo de una aplicación distribuida, con Backend y Frontend desacoplados. En el backend estamos usando Laravel con Sanctum y Fortify. Más información de la serie en el Manual del desarrollo de API con Laravel.
En este artículo vamos a encargarnos de describir una posibilidad para implementar en nuestro backend muy necesaria. Se trata de realizar la operativa de recordar la clave, fundamental para darle soporte al usuario en el caso de que se la haya olvidado su contraseña y no pueda hacer inicio de sesión.
Básicamente nuestro trabajo será proporcionar una ruta desde donde se solicite el envío de la notificación al usuario con el link para crear una nueva clave. Además, en el frontend colocaremos el formulario para generar una nueva clave.
Para comenzar el proceso en el frontend tenemos que crear un formulario que envíe por POST el email del usuario sobre el que queremos operar, aquel sobre el que se desea crear una nueva clave. Este formulario se enviará a la ruta /forgot-password
.
Fortify tiene ya todo lo necesario para componer el email que debe permitir al usuario recordar la clave. Solo tenemos que asegurarnos de los siguientes requisitos que vamos a describir.
En el artículo Modificaciones en el backend para recordar la clave de un usuario con Laravel Fortify encuentras los siguientes apartados de interés.
Activar la funcionalidad de reset password
Fortify debe tener activada la funcionalidad de resetear el password. Esto se hace en el archivo config/fortify.php
'features' => [
// varias funcionalidades…
Features::resetPasswords(),
]
Simplemente debemos verificar que la línea de la funcionalidad de resetPasswords
está activada.
Activar Cors para la ruta 'forgot-password',
En el archivo de configuración de Cors necesitaremos asegurarnos también de que esté activa la ruta de 'forgot-password
'. Esto lo conseguiremos activando la ruta en el array de paths, si es que no la teníamos ya registrada.
'paths' => [
'api/*',
'sanctum/csrf-cookie',
'login',
'register',
'logout',
'/email/verification-notification',
'forgot-password',
'reset-password',
],
Además observarás que también tenemos 'reset-password
' entre las rutas con Cors. Esta ruta la necesitaremos también un poco más adelante.
Problema de generación de la ruta para resetear la clave
Según nos advierten en la documentación de Laravel Fortify, cuando se genera el enlace para que el usuario pueda resetear la clave, incluyendo el token necesario, se usa como referencia una ruta del backend donde tiene la vista con el formulario para que el usuario pueda escribir la nueva clave.
Nuestro problema es que las rutas del backend están desactivadas, pues este backend no tiene vistas, ya que estamos usándolo solo como un API. Esto ocurre porque en la configuración de Fortify marcamos la opción:
'views' => false,
Esto produjo que no se registren las rutas de las vistas y por lo tanto no se podrá generar el enlace para resetear la clave.
Al intentar componer el email con el enlace para resetear la clave el backend lanzará un error 500 con el siguiente mensaje: Route [password.reset] not defined.
Para solucionarlo podríamos crear una ruta en nuestro backend con el "name" "password.reset". En ese caso el backend tendría que generar además un formulario para reescribir la clave, pero llegaríamos a un callejón sin salida porque este backend está manipulado para funcionar solamente como un API, sin páginas visibles.
Lo mejor es cambiar la funcionalidad de Laravel para crear el enlace con el token. Esto es algo que está explicado en la documentación en la sección Reset link customization. De todos modos te lo vamos a explicar aquí.
Redefinir la función que genera el enlace para resetear la clave
Entendido el problema anterior, nuestra solución preferida consiste en simplemente cambiar el enlace que llevaría a la ruta desde la que se puede resetear la clave. En vez de llevar al usuario a la ruta del backend lo llevaremos a una ruta en nuestra aplicación frontend.
Para ello tenemos que hacer unas modificaciones en el archivo AuthServiceProvider.php
que tenemos en la ruta app/Providers/AuthServiceProvider.php
.
En ese archivo tenemos que comenzar haciendo el uso de una clase llamada ResetPassword
que vamos a necesitar en su namespace:
use Illuminate\Auth\Notifications\ResetPassword;
Luego tenemos que invocar al método estático createUrlUsing()
de ResetPassword
. En ese método estático le vamos a enviar como parámetro el código de la función que se encargará de crear el enlace de resetear la clave.
Esa función recibe como parámetros el usuario y el token. Debe devolver la cadena con la ruta donde ese usuario debe cambiar su clave. Podría ser algo como lo que sigue:
public function boot()
{
$this->registerPolicies();
ResetPassword::createUrlUsing(function ($user, string $token) {
return env('FRONTEND_URL') . '/reset-password?token='.$token;
});
}
También podríamos enviar el email de ese usuario si lo deseamos:
public function boot()
{
$this->registerPolicies();
ResetPassword::createUrlUsing(function ($user, string $token) {
return env('FRONTEND_URL') . '/reset-password?token='.$token . '&email=' . $user->email;
});
}
El email no es necesario enviarlo realmente, dado que el usuario lo puede introducir a mano, pero si lo enviamos mediante el querystring podríamos poblar el campo de formulario y evitaríamos al usuario tener que introducirlo.
Enviar los datos del la nueva clave
Ahora ya solamente quedaría componer en el frontend un formulario para enviar los datos de la nueva clave.
Ese formulario necesitaría enviar al backend el token de vuelta, junto con el email del usuario y la clave, así como la conformación de la clave. La ruta donde se espera recibir ese formulario es /reset-password
y el método POST.
Esa parte la veremos cuando lleguemos a componer nuestro frontend.
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...