Etiquetas: Android, Kotlin, Firebase, Google, Jetpack Compose.
Introducción
GoogleAuthLab es un proyecto de aprendizaje en el que exploré la implementación de la autenticación con Google en Android utilizando Kotlin, Jetpack Compose, Credential Manager y Firebase Authentication.
En este primer artículo construiremos una implementación básica del inicio de sesión, desde la configuración de Firebase hasta la conexión de las operaciones de autenticación con un botón en Compose. El objetivo es comprender cómo funciona el proceso antes de introducir capas adicionales de abstracción.
Este tutorial forma parte de una serie de artículos en la que iremos mejorando el código progresivamente, incorporando un ViewModel, un repositorio y, posteriormente, herramientas como Hilt para la inyección de dependencias.
Puedes consultar el código fuente del proyecto en GitHub: Mictlanti/GoogleAuthLab.
1. Primeros pasos
1.1. Crear un proyecto de Firebase
Crea un nuevo proyecto en Firebase Console y registra tu aplicación Android utilizando el nombre del paquete definido en la configuración del módulo de la aplicación.
Descarga el archivo google-services.json y colócalo dentro de la carpeta app del proyecto.
Después, habilita Google como proveedor de autenticación en la sección Authentication de Firebase. Completa los campos solicitados, incluido el correo de asistencia del proyecto, y guarda los cambios.
1.2. Configurar las huellas digitales SHA
Las huellas SHA se calculan a partir del certificado con el que se firma la aplicación y ayudan a configurar su integración con los servicios de Google.
Para obtenerlas desde Android Studio, sigue estos pasos:
- Abre la ventana de Gradle, situada en el lateral de Android Studio.
- Busca y selecciona Execute Gradle Task.
- Ejecuta la tarea
signingReport. - Espera a que finalice y localiza los valores correspondientes a
SHA1ySHA-256.
Regresa a Firebase Console y ve a Configuración del proyecto → General → Tus apps → Huellas digitales del certificado.
Añade la huella SHA-1 y, cuando corresponda, la SHA-256. Guarda los cambios.
1.3. Obtener el Web Client ID
Para solicitar el ID token de Google mediante Credential Manager, necesitamos el identificador de cliente web.
Dentro de Firebase Console, ve a Authentication → Método de acceso → Google y busca la sección de configuración del SDK web. Copia el ID del cliente web (Web Client ID).
En Android Studio, abre res/values/strings.xml y añade el identificador de la siguiente manera:
<string name="web_client_id">TU_WEB_CLIENT_ID.apps.googleusercontent.com</string>
Sustituye el valor de ejemplo por el ID de cliente web de tu proyecto.
1.4. Configurar las dependencias
Antes de implementar la autenticación, necesitamos incorporar las bibliotecas que utilizaremos.
En este proyecto, las dependencias se organizan en los siguientes grupos:
- Firebase Authentication: gestión de la autenticación.
- Credential Manager y Google Identity: obtención de las credenciales de Google.
- Google Services: integración de la configuración de Firebase con el proyecto Android.
Para consultar las dependencias y sus versiones, revisa los archivos de configuración de GoogleAuthLab en GitHub.
2. Construcción de la UI
Antes de implementar la autenticación, necesitamos dos pantallas: Login y Profile.
Puedes diseñarlas a tu gusto con Jetpack Compose, asegurándote de incluir:
- Un botón en
Loginpara iniciar sesión con Google. - Un botón en
Profilepara cerrar sesión. - Los elementos visuales necesarios para identificar al usuario autenticado.
Si quieres seguir el mismo diseño utilizado en este proyecto, puedes tomar como referencia las siguientes imágenes.
Por ahora, céntrate en construir la interfaz. En los siguientes apartados conectaremos los botones con la lógica de autenticación.
3. Construir la capa de autenticación
3.1. AuthRes
Primero necesitamos crear una clase sellada que nos permita distinguir entre una operación exitosa y otra que haya producido un error.
Dentro de la carpeta principal del proyecto, crea la carpeta data y, dentro de ella, otra llamada util. Finalmente, crea el archivo AuthRes.kt en la ruta data/util/AuthRes.kt.
Esta clase contempla dos posibles resultados:
-
Success<T>: representa una operación exitosa y contiene el dato devuelto, cuyo tipo puede variar según la operación. -
Error: representa un fallo y contiene un mensaje que describe el error.
La palabra clave sealed permite restringir las subclases directas de AuthRes, mientras que out T declara el parámetro genérico como covariante. Esto permite, por ejemplo, que un valor de tipo AuthRes<String> pueda utilizarse donde se espera un AuthRes<Any>.
3.2. CredentialManager
Dentro de la carpeta data, creamos una nueva llamada remote. Dentro de ella, creamos la carpeta auth, donde guardaremos nuestro archivo CredentialManager.kt.
Ruta: data/remote/auth/CredentialManager.kt
3.2.1. getGoogleIdToken
Dentro de nuestra clase, implementamos el método getGoogleIdToken().
La función sigue cuatro pasos:
- Crea una instancia de Credential Manager de AndroidX.
- Intenta obtener una credencial de una cuenta previamente autorizada. Si no encuentra ninguna, vuelve a intentarlo sin limitar la solicitud a cuentas previamente autorizadas.
- Comprueba que la credencial recibida sea del tipo esperado y extrae el ID token de Google.
- Devuelve el token mediante
AuthRes.Successo un error medianteAuthRes.Error.
Las excepciones contempladas permiten comunicar distintos fallos, como un problema al procesar el token o un error al solicitar la credencial.
Es importante recordar que este método obtiene el ID token de Google, pero todavía no inicia sesión en Firebase. Ese paso lo implementaremos con AuthManager.
3.2.2. Solicitar credenciales
Para separar la solicitud de credenciales de su procesamiento, creamos el método privado requestCredential().
Este método construye una solicitud para obtener una credencial de Google y devuelve la credencial recibida.
Hay dos configuraciones importantes:
-
setServerClientId(webClientId): establece el ID de cliente web que utilizamos para solicitar el token de Google. -
setFilterByAuthorizedAccounts(filterAuthorizedAccounts): permite controlar si la solicitud se limita a cuentas que ya han autorizado la aplicación.
De esta forma, podemos reutilizar la misma lógica de solicitud con distintas configuraciones, sin duplicar el código.
3.2.3. Limpiar el estado de las credenciales
Este método permite solicitar a Credential Manager que limpie el estado de las credenciales utilizadas anteriormente. Puede ser útil durante el cierre de sesión para que los siguientes intentos de autenticación no dependan del estado conservado por Credential Manager.
Sin embargo, esta operación no cierra la sesión de Firebase. La sesión de Firebase Authentication debe cerrarse por separado, como veremos más adelante.
3.3. AuthManager
Ahora creamos la clase AuthManager dentro de la carpeta auth. Su responsabilidad será gestionar las operaciones de autenticación mediante Firebase Authentication.
Comenzamos obteniendo la instancia de Firebase Auth:
FirebaseAuth.getInstance() nos proporciona la instancia de Firebase Authentication que utilizaremos para realizar operaciones como iniciar sesión y cerrar sesión.
3.3.1. SignInWithGoogle
Una vez que obtenemos el ID token de Google, necesitamos utilizarlo para autenticar al usuario en Firebase Authentication.
Para ello, añadimos el método signInWithGoogle() a AuthManager.
El método sigue estos pasos:
-
Crear la credencial:
GoogleAuthProvider.getCredential()utiliza el ID token obtenido anteriormente para construir una credencial compatible con Firebase Authentication. El segundo parámetro,null, corresponde al access token, que no estamos utilizando en este flujo. -
Autenticar con Firebase:
signInWithCredential(credential)envía la credencial a Firebase para intentar iniciar sesión. -
Esperar el resultado:
.await()permite esperar el resultado de la operación de forma suspendible, sin bloquear el hilo mientras se completa la petición. Para utilizarlo, el proyecto debe incluir la extensión de corrutinas de Google Play Services correspondiente. -
Validar el usuario: comprobamos que
authResult.userno seanull. Si Firebase no devuelve un usuario, respondemos conAuthRes.Error. -
Devolver el resultado: si todo sale bien, devolvemos
AuthRes.Success(user), dondeuseres una instancia deFirebaseUser. Si ocurre una excepción, devolvemos un error.
De esta manera, AuthManager se encarga de la autenticación con Firebase, mientras que la obtención del ID token de Google queda en la clase responsable de gestionar Credential Manager.
3.3.2. Observar el estado de autenticación y cerrar sesión
Además de iniciar sesión, necesitamos saber cuándo cambia el estado de autenticación y ofrecer una forma de cerrar la sesión actual. Para ello, añadimos dos métodos a AuthManager.
Observar el estado de autenticación
Esta función expone el estado de autenticación de Firebase mediante un Flow<FirebaseUser?>. Esto permite que otras partes de la aplicación observen si existe un usuario autenticado y reaccionen cuando cambia la sesión.
Veamos sus partes principales:
-
Crear el listener:
FirebaseAuth.AuthStateListenerrecibe notificaciones cuando cambia el estado de autenticación y permite obtener el usuario actual medianteauth.currentUser. Si no hay una sesión activa, el valor seránull. -
Registrar el listener:
addAuthStateListener(listener)permite que Firebase notifique los cambios de estado. -
Emitir el estado inicial:
trySend(firebaseAuth.currentUser)envía también el estado actual al flujo. Así, quien lo observe no tiene que esperar a un cambio posterior para conocer la situación de la sesión. -
Liberar recursos:
awaitClosepermite eliminar el listener cuando el flujo deja de estar activo. Esto evita conservar un listener innecesariamente.
Cerrar sesión
Esta segunda función es más sencilla: firebaseAuth.signOut() cierra la sesión actual en Firebase Authentication.
Al hacerlo, observeAuthState() puede emitir el nuevo estado —normalmente null— para que las partes de la aplicación que observan el flujo reaccionen, por ejemplo, mostrando la pantalla de inicio de sesión en lugar del perfil.
Con esto ya tenemos las operaciones básicas de autenticación preparadas. En el siguiente apartado las conectaremos con el botón de inicio de sesión de Jetpack Compose para probar el flujo completo.
4. Conectar Google Sign-In con Jetpack Compose
Ya tenemos las piezas necesarias para implementar la autenticación. El último paso consiste en conectar nuestras clases GoogleAuthClient y AuthManager con el botón Sign in with Google.
En este ejemplo, utilizamos rememberCoroutineScope() para ejecutar las funciones suspendibles cuando el usuario pulsa el botón. Primero obtenemos el ID token de Google y, si la operación tiene éxito, lo utilizamos para iniciar sesión en Firebase Authentication.
Si ambos pasos se completan correctamente, mostramos un mensaje de confirmación. Si ocurre un error durante cualquiera de ellos, mostramos el mensaje correspondiente.
5. Probar la autenticación
Es momento de ejecutar la aplicación y comprobar el flujo:
- Abre la pantalla que contiene el botón Sign in with Google.
- Pulsa el botón y completa el proceso de selección de cuenta, si se solicita.
- Comprueba que Firebase acepta las credenciales y que aparece el mensaje de éxito.
- Si la operación falla, revisa el mensaje de error y verifica la configuración de Firebase, las huellas SHA y el Web Client ID.
Recuerda que el comportamiento del selector de cuentas puede variar según las credenciales disponibles y el estado de la cuenta en el dispositivo.
Conclusión
¡Ya tenemos una implementación básica de Google Sign-In en Android con Kotlin, Jetpack Compose, Credential Manager y Firebase Authentication!
A lo largo de este tutorial configuramos Firebase, obtuvimos el ID token de Google y lo utilizamos para autenticar al usuario en Firebase. Finalmente, conectamos las operaciones con un botón de Compose, sin introducir todavía un ViewModel ni un repositorio.
Esta implementación nos permite comprender el flujo de autenticación antes de añadir más capas de abstracción. Sin embargo, mantener toda esta lógica directamente en la interfaz no es lo ideal para una aplicación que vaya a crecer.
En el siguiente artículo, refactorizaremos el código para incorporar un ViewModel y un AuthRepository. Veremos cómo separar las responsabilidades, gestionar el estado de la interfaz y preparar la autenticación para que sea más fácil de mantener y probar.
Gracias por leer el artículo. Puedes consultar el código fuente del proyecto en GitHub:












Top comments (0)