Autenticación de usuarios con Google en React (firebase)

Autenticar usuarios desde tu propio servidor es un proceso complicado y puede abrir muchas brechas de seguridad ya que es necesario almacenar contraseñas y otra información sensible para poder verificar su identidad. Google ofrece un servicio gratuito para autenticar a tus usuarios y se encarga de toda la parte complicada. En este artículo aprenderás a configurar autenticación con Google en tu React app.

En este artículo aprenderás:

  1. ¿Cómo crear un proyecto en Google Firebase?
  2. ¿Cómo configurar firebase en React?
  3. ¿Cómo configurar los componentes de React?

¿Cómo crear un proyecto en Google Firebase?

  1. Ve a la consola de google
  2. Crea un nuevo proyecto
  3. Dependiendo de tus necesidades, puedes habilitar o deshabilitar google analytics. Para este ejemplo lo vamos a deshabilitar.
  4. Haz clic en la tarjeta de 'Autenticación', y haz click en comenzar.
  5. Selecciona google como proveedor de autenticación
  6. Ve a la configuración del proyecto (arriba a la izquierda)
  7. Guarda el ID del proyecto y también la Clave de API web para la configuración desde tu aplicación.

¿Cómo configurar firebase en React?

Estructura de directorios recomendada

Instala las dependencias de firebase

npm i firebase

Variables de entorno

Utilizamos el archivo .env para configurar nuestras variables de entorno para que permanezcan ocultas. En caso de que requieras desplegar tu aplicación al público asegúrate de que estas variables sean privadas.

// .env
REACT_APP_PUBLIC_FIREBASE_API_KEY = claveDeApi;
REACT_APP_PUBLIC_FIREBASE_AUTH_DOMAIN = idDelproyecto.firebaseapp.com;
REACT_APP_PUBLIC_FIREBASE_PROJECT_ID = idDelproyecto;

Archivo de configuración de Firebase

// src/lib/firebase.js
import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.REACT_APP_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PUBLIC_FIREBASE_PROJECT_ID,
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth(app);

Archivo de configuración de autenticación

En este archivo vamos a declarar el contexto que va a englobar a la aplicación para proveer el servicio de autenticación dentro de la función AuthProvider.

Nota: En la función formatUser usamos solamente algunas propiedades del usuario, si requieres más o menos información lo puedes ajustar a tus necesidades.

// src/lib/auth.js
import React, { useState, useEffect, useContext, createContext } from "react";
import { auth } from "./firebase";
import {
  signInWithPopup,
  GoogleAuthProvider,
  signOut,
  onAuthStateChanged,
} from "firebase/auth";

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const auth = useProvideAuth();
  return <AuthContext.Provider value={auth}>{children}</AuthContext.Provider>;
}

export const useAuth = () => {
  return useContext(AuthContext);
};

function useProvideAuth() {
  const [user, setUser] = useState();

  const handleUser = async (rawUser) => {
    if (rawUser) {
      const user = formatUser(rawUser);
      const { token } = user;
      setUser(user);
      return user;
    } else {
      setUser(undefined);
      return false;
    }
  };

  const signinWithGoogle = async () => {
    const provider = new GoogleAuthProvider();
    return signInWithPopup(auth, provider)
      .then((response) => {
        handleUser(response.user);
      })
      .catch((err) => {
        console.error(error);
        // Handle Errors here.
      });
  };

  const signout = async () => {
    return signOut(auth)
      .then(() => {
        handleUser(false);
      })
      .catch((err) => {
        console.error(err);
        //Handle error
      });
  };

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        handleUser(user);
      } else {
        handleUser(false);
      }
    });
    return unsubscribe;
  }, []);
  return {
    user,
    signinWithGoogle,
    signout,
  };
}

const formatUser = (user) => {
  return {
    uid: user.uid,
    email: user.email,
    name: user.displayName,
    token: user.stsTokenManager.accessToken,
    provider: user.providerData[0].providerId,
    photoUrl: user.photoURL,
  };
};

¿Cómo configurar los componentes de React?

App.js

Aquí es donde vamos a utilizar el contexto que creamos en el archivo de autenticación.

// src/App.jsx
import { Dashboard } from "./components/Dashboard";
import { SignIn } from "./components/Signin";
import { AuthProvider } from "./lib/auth";

const App = () => {
  return (
    <AuthProvider>
      <SignIn />
      <Dashboard />
    </AuthProvider>
  );
};

export default App;

Configuración de renderizado condicional dependiendo si el usuario está autenticado o no

SignIn.jsx

// src/components/SignIn.jsx
import React from "react";
import { useAuth } from "../lib/auth";

export const SignIn = () => {
  const auth = useAuth();

  const handleGoogleSignIn = async () => {
    await auth.signinWithGoogle();
  };

  return (
    <>
      {!auth.user ? (
        <button onClick={handleGoogleSignIn}>
          <span>Iniciar sesión con Google</span>
        </button>
      ) : null}
    </>
  );
};

Dashboard.jsx

// src/components/Dashboard.jsx
import React from "react";
import { useAuth } from "../lib/auth";

export const Dashboard = () => {
  const auth = useAuth();

  const handleGoogleSignOut = async () => {
    await auth.signout();
  };
  return (
    <>
      {auth.user ? (
        <>
          <h1>Bienvenido, {auth.user.name}!</h1>
          <button onClick={handleGoogleSignOut}>Cerrar Sesión</button>
        </>
      ) : null}
    </>
  );
};

Ayúdame a mejorar este artículo

¿Quisieras complementar este artículo o encontraste algún error?¡Excelente! Envíame un correo.

  • seb@sebastianfdz.com