DEV Community

Cover image for Laravel: Migrar de Passport a Sanctum
Marco Ramírez
Marco Ramírez

Posted on

Laravel: Migrar de Passport a Sanctum

Mis chamacos ¿me extrañaron?

Espero que no, amigos. Estuve muy alejado por cuestiones laborales de este bonito espacio, pero a la vez quisiera comentarles que he abierto un espacio dedicado a todos los apuntes, tutoriales, guías y demás posts que vaya armando aquí o en él.

Su nombre es The Dev Gang y tiene como objetivo el conglomerar ahí todo el conocimiento que les traigo en español y ¿por qué no? en un futuro que haya más colaboradores (algunos dirán ¡NO MAMES, STERNIE!, quédate aquí), pero pues la verdad es que lo hago para probar AdSense y ver si aunque sea cae para los cigarros con ello. Pueden verlo desde aquí.

Dicho lo anterior, vamos a darle con este bonito post.

Verán, al trabajar en este caso con Laravel, nos encontramos en ocasiones que deseamos tener el clásico comportamiento de autenticación de nuestras REST APIs, por lo que para ello tenemos dos alternativas: Passport y Sanctum. Passport es una librería que provee de un servidor OAUTH2 para poder realizar este trabajo. Passport hace una implementación del mismo en minutos y con la que podemos contar con tokens JWT para poder acceder a endpoints restringidos en nuestra API.

Ahora bien, Laravel, desde la versión 7, integró una nueva librería para autenticación más liviana que Passport y que a la vez puede generar múltiples tokens para los diferentes dispositivos que acceden a la API. Ahora bien, eso no quiere decir que Passport no lo haga, sin embargo, la pregunta del millón de dólares sería la siguiente:

¿Tu proceso de negocio requiere OAUTH2?

Si tu respuesta es sí, usa Passport, si no, puedes decantarte por Sanctum, que en mi opinión es más económico, en cuanto a uso de recursos del sistema se refiere y a que en este caso, las tokens generadas por Sanctum son más duraderas (hasta años) y pueden ser revocadas manualmente. La desventaja que le veo a Sanctum es que como tal, no puedes renovar token alguna, pero esa no es como tal la intención de Sanctum, misma que sí es de Passport el refrescar una token.

Si estás en el caso de uso de que no necesitas OAUTH2 o simplemente quieres cambiarte a Sanctum proveniente de Passport, entonces este post es para ti, te contaré el cómo migrarte de Passport a Sanctum en poco tiempo y poder así tener un proceso más eficiente en cuanto a autenticación se refiere.

ATENCIÓN: Migrar de Passport a Sanctum es un proceso que debes pensar muy bien y más si es que tienes muchísimos usuarios registrados en tu aplicación, puesto que el realizar dicha migración involucraría, en el caso más extremo, el solicitar a todos y cada uno de los usuarios registrados que vuelvan a ingresar una nueva contraseña, así que como decimos en México “tantéale el agua a los camotes”

Pasos para migrar

Primeramente, debemos instalar Sanctum, esto lo hacemos con la siguiente línea:

composer require laravel/sanctum

Posterior a eso, ejecuta la siguiente línea en tu terminal:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"

Esto publicará los archivos de configuración de Sanctum a nuestra carpeta config. Esto incluye archivos de migración para la base de datos por lo que necesitas ejecutar:

php artisan migrate

Una vez realizada la instalación, es momento de manipular lo siguiente:

Ve al archivo config/auth.php y cambia la guard que desees tener bajo Sanctum, por lo general es la de API la que queremos tener tokenizada, por lo que tendrás:

'api' => [
    'driver' => 'passport',
    'provider' => 'users',
    'hash' => false,
 ],
Enter fullscreen mode Exit fullscreen mode

Cambia passport por sanctum.

Ahora, pasa hacia la clase User, esta se encuentra dentro de tu carpeta app/models. Busca esta línea:

use Laravel\Passport\HasApiTokens;
Enter fullscreen mode Exit fullscreen mode

y cámbiala por esta:

use Laravel\Sanctum\HasApiTokens;
Enter fullscreen mode Exit fullscreen mode

Con esto bastará en la parte de nuestro modelo, pero es hora de meternos al servicio donde generamos el login y el registro. Comencemos con el login. Si tienes un método como el siguiente:

private function getAuthAndRefreshToken($request, $email, $password) {
        $oClient = OClient::where('password_client', 1)->first();

        $request->request->add([
            'grant_type' => 'password',
            'client_id' => $oClient->id,
            'client_secret' => $oClient->secret,
            'username' => $email,
            'password' => $password,
            'scope' => '*',
        ]);

        $response = Route::dispatch(Request::create('oauth/token', 'POST'));

        $result = json_decode((string) $response->getContent(), true);
        $result['success'] = !isset($result['error']);

        return $result;
    }
Enter fullscreen mode Exit fullscreen mode

Entonces tenemos que hacer un refactor. Primero cambia de getAuthAndRefreshToken a getToken, posteriormente cambia los parámetros que recibirás a $email, $password y $deviceID. El código en su interior se va, quedando primeramente así:

private function getToken($email, $password, $deviceID)
{

}
Enter fullscreen mode Exit fullscreen mode

Ingresa esta línea de código dentro del método:

$user = User::where('email', $email)->first();
Enter fullscreen mode Exit fullscreen mode

Esto nos buscará el usuario con el correo electrónico que el usuario nos solicita. Si encuentra el usuario, proseguimos, en caso contrario, se regresa una respuesta de tipo 401 o 403 para denegar el acceso. Esto a la vez lo hacemos con este condicional:

if (null !== $user || !Hash::check($password, $user->password)) {
    return ['success' => false, 'message' => 'Correo electrónico o contraseña incorrectas'];
}
Enter fullscreen mode Exit fullscreen mode

Además de checar de que el usuario que buscamos existe, confirmamos que la contraseña es correcta entregando el password que nos da el usuario y confirmando que los hashes coincidan.

En caso que la validación sea correcta, podemos regresar la token sin problemas de esta forma:

return [
    'success' => true,
    'access_token' => $user->createToken($deviceID)->plainTextToken
];
Enter fullscreen mode Exit fullscreen mode

Con esto bastará para el login y para el registro, ahora bien, en los métodos que utilices para el controlador del login y del registro, cuida de sustituir la línea:

$result = $this->getTokenAndRefreshToken(request(), request('email'), request('password'));
Enter fullscreen mode Exit fullscreen mode

Por esta otra:

$result = $this->getToken($user->email, $password, $request->device_id);
Enter fullscreen mode Exit fullscreen mode

Prueba ahora tu implementación, si te entrega un objeto similar al siguiente:

{
    "success": true,
    "access_token": "1|1QjmwWuwL3EocZcErFPw0RoBLYBT6mO9GNblOVVHd1f0ed6a"
}
Enter fullscreen mode Exit fullscreen mode

La migración fue completada con éxito. Ahora es tiempo de hacer limpieza. Dentro de tu implementación, puedes eliminar lo siguiente:

  1. Las tablas que comienzan con OAUTH en la base de datos.
  2. Cualquier referencia a Passport que encuentres en tu código.
  3. Si hiciste la implementación de un middleware denominado CheckClientCredentials, elimínalo.
  4. En el archivo app/Http/Kernel.php, elimina esta línea (solo aplica si implementaste el CheckClientCredentials):
'CheckClientCredentials' => \App\Http\Middleware\CheckClientCredentials::class,
Enter fullscreen mode Exit fullscreen mode
  1. Elimina del composer.json las líneas referentes a Passport.
  2. Ejecuta composer update.

Ya con esto, puedes implementar esta autenticación como de costumbre.

Ya para terminar, debo mencionarte que las tokens generadas por Sanctum, se utilizan como tokens BEARER, por lo que estas las entregas a tu request, por medio de la cabecera Authorization de esta manera:

Authorization: Bearer 1|1QjmwWuwL3EocZcErFPw0RoBLYBT6mO9GNblOVVHd1f0ed6a

Para cada lenguaje y aplicación es diferente, por lo que dejo a tu criterio cómo la debes implementar en el frontend.

Pues bien, espero que les haya gustado este post y procuraré tenerles muchos más posts de estos y ya no ausentarme. Por el momento estaré migrando el contenido a The Dev Gang, pero como les dije, por aquí seguiré escribiendo también.

Happy coding!

Top comments (0)