Firebase Authentication: vinculación de usuarios

Firebase Authentication

Cómo vincular usuarios de Firebase Authentication y Laravel Passport

Aprenda a crear un flujo de autenticación que vincule a sus usuarios de Firebase Authentication con sus usuarios de Laravel Passport usando FirebaseUI para la web.

Esto puede ser útil al crear una API con Laravel donde sus usuarios iniciarán sesión en su aplicación web usando FirebaseUI de Google.


Algo de contexto sobre las tecnologías utilizadas

FirebaseUI para la Web

 

FirebaseUI es una biblioteca construida sobre el SDK de Firebase Authentication que proporciona flujos de IU integrados para usar en tu aplicación. […]
(https://firebase.google.com/docs/auth/web/firebaseui)

FirebaseUI para la web de hecho le brinda una forma muy simple y segura de agregar una interfaz reactiva de inicio de sesión / registro de Javascript con múltiples proveedores como Facebook, Google, GitHub o incluso un buen correo electrónico / contraseña a su aplicación web.

Construido sobre Firebase Authentication, significa que su servidor nunca verá las credenciales de sus usuarios, ya que solo las envía y almacena Google.

Una característica muy interesante es que mientras usen el mismo correo electrónico, sus usuarios siempre tendrán una sola cuenta sin importar el proveedor que usen.

Pasaporte Laravel

(Consulte https://laravel.com/docs/7.x/passport para obtener más detalles)

Laravel Passport es un complemento muy poderoso para Laravel Framework que proporciona una implementación completa del servidor OAuth2. Esto le dará la capacidad de usar tokens seguros en sus solicitudes de API con muchas posibilidades, como alcances para sus rutas, vida útil para sus tokens…

Esta guía asume…

Que ya ha creado una API PHP usando Laravel 7.xy ha instalado y configurado Laravel Passport y que usa FirebaseUI para registrar e iniciar sesión en sus usuarios.

Que tiene un buen conocimiento de cómo usar su marco frontend para enviar solicitudes de API y reaccionar ante los datos recibidos de forma asincrónica.

Personalmente, analicé este problema con una interfaz web que usa Vuejs en mente, pero Firebase Authentication también funciona con iOS, Android, C ++ y más. Por tanto, es una muy buena opción para un flujo de trabajo de autenticación.

Si aún no está usando Laravel Passport

Le sugiero que lea su documentación y siga este gran tutorial para tener un punto de partida claro.

Si aún no está usando FirebaseUI

FirebaseUI es muy simple y poderoso para implementar el flujo de autenticación. Consulte esta documentación oficial para utilizarla.

¿Cómo se vincularán los usuarios de Firebase y Laravel?

Como se describió anteriormente, con Firebase Authentication, independientemente del proveedor de inicio de sesión que elijan sus usuarios, siempre recibirá el mismo tipo de datos de Google y sus usuarios siempre tendrán solo una cuenta por correo electrónico en su base de datos de Firebase Authentication.

Toda esta lógica la proporciona Google, lo cual es muy conveniente. Por nuestra parte, podemos acceder al correo electrónico de los usuarios, displayName, Avatar y .. UID (User ID).

Vincule a sus usuarios de Laravel con sus respectivos UID de Firebase

Entonces, la forma más sencilla de vincular a sus usuarios de Laravel con sus usuarios de Firebase es usar su UID, que nunca cambiará incluso si el usuario inicia sesión con otro proveedor (asumiendo que usan el mismo correo electrónico para todos los proveedores).

Le sugiero que agregue una columna específica a la tabla de su usuario, como FirebaseUID o lo que se adapte a su nomenclatura.

Luego, todo lo que tendremos que hacer es verificar si el UID recuperado ya existe en nuestra tabla de usuarios de Laravel y si no, crear un nuevo usuario con este UID.

El flujo de trabajo de inicio de sesión / registro

Para comenzar, echemos un vistazo al flujo de trabajo deseado para nuestra aplicación web y API.

Firebase Authentication
Flujo de autenticación usando FirebaseUI y Laravel Passport

Como puede ver, el primer paso es solicitar el token de una credencial de Firebase. Nuevamente, lo bueno de Firebase Authentication es que, sea cual sea el proveedor compatible que elija su usuario (Facebook, Google …), siempre terminará usando un token de ID de Firebase. Que es lo que necesitamos.

Recuperar el token de credenciales de Firebase Authentication

El token de Firebase es solo un JWT (JSON Web Tokens). Como tal, puede inspeccionarlos usando jwt.io y usar una biblioteca de terceros para manejarlos.

En caso de que se lo pregunte, para solicitar un token de ID de Firebase al iniciar sesión en su usuario con FirebaseUI para la web, use la función getIdToken() de Javascript.

En la devolución de llamada de SignInSuccessWithAuthResult:

signInSuccessWithAuthResult: function(authResult, redirectUrl) {

  authResult.user.getIdToken().then(function(accessToken) {
    // I personally store this token using Vuex 
    // so i can watch it and detect its change to act accordingly. 
  })
  
  return false;
  
}

En la función onAuthStateChanged:

firebase.auth().onAuthStateChanged(user => {

  user.getIdToken().then(function(accessToken) {
    // I personally store this token using Vuex 
    // so i can watch it and detect its change to act accordingly. 
  })   
  
});

Envía la credencial de autenticación de Firebase a tu API

El siguiente paso es enviar el token de esta credencial a nuestra API de Laravel para verificarlo y generar un token de Passport que podamos usar para autenticar nuestras futuras solicitudes de API.

Supongo que ya sabe cómo enviar una solicitud a su API de Laravel (yo personalmente uso Axios). También debería tener la configuración de Laravel Passport y trabajar con su propio correo electrónico y contraseña.

Para este tutorial, solo enviaremos el token de nuestra credencial de Firebase como una carga útil de solicitud a nuestra API, ya que esto ya es suficiente para tener un puente seguro entre Firebase Auth y Laravel Passport.

Entonces, nuestra URL de solicitud podría verse comoe https://api.yourapp.com/login con un cuerpo JSON como:

{
  "Firebasetoken": "your-firebase-auth-credential-token"
}

Agregar Laravel-Firebase

Ahora, necesitamos usar este token para crear o iniciar sesión en su usuario y enviar un token de Passport que podamos usar en futuras solicitudes de API.

Para verificar el token de una credencial de autenticación de Firebase en nuestra API, debemos verificar con el servidor de Google si el token es válido (tiene el formato correcto, existe en la base de datos de Google y no está vencido).

Para hacer eso, podemos usar una muy buena implementación del SDK de autenticación de Firebase para Laravel: Laravel Firebase de Kreait.

Para instalarlo usando el compositor, ejecute:

composer require Kreait/laravel-firebase

Si no utiliza el descubrimiento automático de paquetes de Laravel, debe agregar el siguiente proveedor de servicios a su config / app.php:

<?php
// config/app.php
return [
    // ...
    'providers' => [
        // ...
        Kreait\Laravel\Firebase\ServiceProvider::class
    ]
    // ...   
];

Una vez hecho esto, debe configurar el paquete para usar su cuenta de servicio Firebase Auth, que es necesaria para autenticar sus solicitudes en los servidores de Firebase.

Para hacerlo, puede agregar lo siguiente en el archivo .env de su Laravel:

FIREBASE_CREDENTIALS=/full/path/to/firebase_credentials.json

 

Por favor, asegúrese de no almacenar este archivo en su repositorio, ya que es un archivo muy confidencial que le da acceso a su cuenta de Firebase.

 

Si no tiene una cuenta de servicio para su proyecto Firebase Auth, siga las instrucciones de Google. Terminará con un archivo JSON de credenciales que debe colocar en algún lugar de su instalación de Laravel.

Es posible que también desee cambiar algunas otras opciones. Si es así, simplemente copie la configuración del paquete usando:

php artisan vendor:publish --provider="Kreait\Laravel\Firebase\ServiceProvider" --tag=config

Para obtener más detalles sobre la instalación y configuración de kreait/laravel-firebase, consulte su documentación.

Verifique el token de la credencial con los servidores de Google.

Entonces, ahora estamos listos para verificar el token de la credencial de autenticación de Firebase con los servidores de Google.

En nuestro flujo de autenticación, para simplificar el proceso, solo usaremos la ruta de login y verificaremos si existe un usuario de Laravel con el UID de Firebase específico.

Si existe, devolvemos un token de acceso personal (y datos adicionales si es necesario). De lo contrario, creamos el usuario y devolvemos la PAT del usuario y los datos adicionales.

Recuerde: utilizamos el UID de autenticación de Firebase para vincular a nuestros usuarios de Firebase con nuestros usuarios de Laravel.

Entonces, con eso en mente, echemos un vistazo a nuestro loginController.php.

Primero, necesitamos agregar el controlador de excepciones proporcionado por Firebase, agregue esto a su loginController.php:

use Firebase\Auth\Token\Exception\InvalidToken;

Entonces, veamos nuestra función de inicio de sesión:

<?php

// Please, note that this code is just an extract of loginController.php
// You should ensure that all datas received are valid and secure.

public function login(Request $request) {
  
  // Launch Firebase Auth
  $auth = app('firebase.auth');
  // Retrieve the Firebase credential's token
  $idTokenString = $request->input('Firebasetoken');

  
  try { // Try to verify the Firebase credential token with Google
    
    $verifiedIdToken = $auth->verifyIdToken($idTokenString);
    
  } catch (\InvalidArgumentException $e) { // If the token has the wrong format
    
    return response()->json([
        'message' => 'Unauthorized - Can\'t parse the token: ' . $e->getMessage()
    ], 401);        
    
  } catch (InvalidToken $e) { // If the token is invalid (expired ...)
    
    return response()->json([
        'message' => 'Unauthorized - Token is invalide: ' . $e->getMessage()
    ], 401);
    
  }

  // Retrieve the UID (User ID) from the verified Firebase credential's token
  $uid = $verifiedIdToken->getClaim('sub');

  // Retrieve the user model linked with the Firebase UID
  $user = User::where('firebaseUID',$uid)->first();
  
  // Here you could check if the user model exist and if not create it
  // For simplicity we will ignore this step

  // Once we got a valid user model
  // Create a Personnal Access Token
  $tokenResult = $user->createToken('Personal Access Token');
  
  // Store the created token
  $token = $tokenResult->token;
  
  // Add a expiration date to the token
  $token->expires_at = Carbon::now()->addWeeks(1);
  
  // Save the token to the user
  $token->save();
  
  // Return a JSON object containing the token datas
  // You may format this object to suit your needs
  return response()->json([
    'id' => $user->id,
    'access_token' => $tokenResult->accessToken,
    'token_type' => 'Bearer',
    'expires_at' => Carbon::parse(
      $tokenResult->token->expires_at
    )->toDateTimeString()
  ]);

}

Al leer los comentarios, debería poder comprender la lógica detrás de este proceso. Pero para dejarlo claro:

1. Recibimos el Firebasetoken y usamos verifyIdToken() para verificar si el token es válido. De lo contrario, InvalidToken maneja los errores.

2. Usamos getClaim('sub') para extraer el UID de autenticación de Firebase.

3. Recuperamos el modelo de User que tiene el mismo UID. Si no hay ninguno, creamos un nuevo usuario con este UID.

4. Usamos createToken('Personal Access Token') para crear un nuevo token de pasaporte vinculado al usuario de nuestro Laravel con la vida útil deseada.

5. Regresamos a nuestra interfaz un objeto JSON que contiene el token de Passport e información adicional.

Tenga en cuenta que esta implementación es muy simple y carece de funciones importantes como ámbitos (para limitar a qué rutas puede acceder su usuario) y más.

Si desea (y le sugiero encarecidamente que lo haga) agregar ámbitos a los tokens de su Passport, eche un vistazo a esta documentación. Personalmente, vinculo mi alcance a las funciones de mis usuarios, por lo que puedo agregar o eliminar fácilmente los derechos de acceso de los usuarios de mi API backend.

Realiza solicitudes de API utilizando su token de Passport

Et voila! Ahora puede usar su token de Passport para autenticar todas las solicitudes futuras de API y limitar las rutas a las que sus usuarios pueden acceder usando alcances y otros métodos.

En su interfaz, le sugiero que almacene este token en Vuex (si usa Vuejs), almacenamiento local o cookies y luego lo busque cada vez que realice una solicitud de API protegida.

Ahora, incluso si alguien usa los datos públicos disponibles para ellos (el token generado, por supuesto, estará fácilmente disponible en los datos locales de sus usuarios) para solicitar su API, estarán limitados a los alcances dados para el token o no estarán autorizados si el token no es válido.

Controles de seguridad adicionales

Hay algunas comprobaciones de seguridad adicionales que sugiero implementar:

1. Asegúrese de usar HTTPS para solicitar su API, para evitar ataques man-in-the-middle.

2. Además, puede utilizar el uso compartido de recursos de origen cruzado (CORS) para permitir solo las solicitudes de API realizadas desde las URL permitidas.


Gracias por leer

Gracias por seguir esta guía. Cubre solo los conceptos básicos de la integración de Firebase Authentication con Laravel Passport, pero espero que haya sido útil para usted.

Recent Post