Saltar al contenido principal

Login con Google en la App Móvil — Finnova

Finnova ofrece "Continuar con Google" como método de autenticación en la app móvil (React Native / Expo), además del login con email y contraseña. Esta página define cómo se integra el flujo de Google Sign-In con el esquema de sesiones de doble token de Finnova (ver Control de Sesiones).


1. Principio clave

Google Sign-In solo se usa para autenticar la identidad del usuario, no para emitir las sesiones de Finnova. El flujo es:

  1. La app obtiene un ID Token de Google (JWT firmado por Google) usando el SDK nativo.
  2. La app envía ese ID Token al backend de Finnova.
  3. El backend verifica el token contra Google, identifica o crea al usuario, y emite sus propios access + refresh tokens.

Las sesiones siguen siendo de Finnova (mismo esquema JWT de 15 min + refresh opaco de 30 días). Google solo prueba "este usuario es quien dice ser".


2. Configuración previa en Google Cloud

En Google Cloud ConsoleAPIs & Services → Credentials, crear OAuth 2.0 Client IDs (uno por plataforma):

Client IDPara qué
iOSApp nativa en iPhone/iPad (requiere el Bundle ID)
AndroidApp nativa en Android (requiere package name + SHA-1 de la firma)
WebEl backend lo usa como audience para verificar los ID tokens

El Web Client ID es el que el backend valida como audience. Los client IDs de iOS/Android se configuran en el SDK del cliente.


3. Librería recomendada

StackLibrería
Expo (managed)@react-native-google-signin/google-signin con development build, o expo-auth-session como alternativa sin módulo nativo
React Native (bare)@react-native-google-signin/google-signin

expo-auth-session funciona en Expo Go pero usa un flujo de navegador. @react-native-google-signin ofrece la UI nativa de Google (mejor UX) pero requiere development/EAS build. Para Finnova se recomienda @react-native-google-signin/google-signin por la experiencia nativa.


4. Flujo de autenticación


5. Verificación del ID Token en el backend

El backend nunca confía en el token sin verificarlo. Usar la librería oficial google-auth-library:

import { OAuth2Client } from 'google-auth-library';

const client = new OAuth2Client();

async function verifyGoogleIdToken(idToken: string) {
const ticket = await client.verifyIdToken({
idToken,
audience: process.env.GOOGLE_WEB_CLIENT_ID, // Web Client ID
});

const payload = ticket.getPayload();
if (!payload) throw new Error('Token inválido');

// Validaciones adicionales
if (!payload.email_verified) {
throw new Error('Email de Google no verificado');
}

return {
googleSub: payload.sub, // ID estable y único del usuario en Google
email: payload.email!,
name: payload.name,
picture: payload.picture,
};
}

La verificación comprueba automáticamente: la firma (con las claves públicas de Google), el audience (que el token sea para nuestra app), el issuer (accounts.google.com) y la expiración.

Identificar al usuario por sub, no por email. El sub es el identificador único e inmutable de Google; el email podría cambiar o reasignarse. El email se usa solo para vincular cuentas existentes.


6. Vinculación de cuentas (account linking)

Un usuario podría registrarse primero con email/contraseña y luego usar "Continuar con Google" (o viceversa) con el mismo correo. Estrategia:

CasoAcción
google_sub ya existeLogin directo a esa cuenta
google_sub nuevo, pero el email ya existe en una cuentaVincular: añadir google_sub a la cuenta existente
google_sub y email ambos nuevosCrear cuenta nueva (sin contraseña)

Vincular por email solo es seguro porque Google ya verificó email_verified: true. Si en el futuro se añaden proveedores que no verifican el email, no se debe vincular automáticamente.

Cambios al modelo de datos

ALTER TABLE users
ADD COLUMN google_sub TEXT UNIQUE, -- NULL si nunca usó Google
ALTER COLUMN password_hash DROP NOT NULL; -- cuentas solo-Google no tienen contraseña

CREATE INDEX idx_users_google_sub ON users(google_sub);

7. A partir de aquí: sesiones de Finnova

Una vez verificado el usuario, el flujo es idéntico al login con email/contraseña descrito en Control de Sesiones:

  • Se crea una fila en sessions con la info del dispositivo.
  • Se emite el par access token (JWT 15 min) + refresh token (opaco 30 días).
  • El refresh token se guarda en SecureStore; el access token en memoria.
  • Aplican los mismos límites de sesiones por plan, revocación y detección de anomalías.

El POST /auth/google reemplaza al POST /auth/login solo en la etapa de verificación de identidad. Todo lo demás (refresh, logout, multidispositivo) no cambia.


8. Consideraciones de seguridad

  • Verificar siempre el token en el backend — nunca confiar en datos de usuario que llegan del cliente sin validar el ID Token con Google.
  • Validar el audience para evitar que un ID Token emitido para otra app sea aceptado.
  • Exigir email_verified antes de vincular por email.
  • No almacenar el ID Token de Google — se usa una sola vez para autenticar y se descarta; lo que persiste son los tokens de Finnova.
  • Logout: cerrar sesión en Finnova revoca la sesión propia; opcionalmente llamar GoogleSignin.signOut() en el cliente para limpiar el estado local de Google.

9. Variables de entorno

GOOGLE_WEB_CLIENT_ID=xxxxxxxx.apps.googleusercontent.com
GOOGLE_IOS_CLIENT_ID=xxxxxxxx.apps.googleusercontent.com
GOOGLE_ANDROID_CLIENT_ID=xxxxxxxx.apps.googleusercontent.com

Solo los client IDs son públicos; Google Sign-In en móvil no requiere un client secret en el cliente.

Referencias