google-identity.client.js
Overview
services/api/src/modules/auth/google-identity.client.js es la capa de proveedor para la verificación de identidad con Google dentro del módulo auth. Importa directamente google-auth-library, usa env.googleClientId para validar el audience, y expone un resultado normalizado que el resto del dominio consume sin manejar el payload bruto del token. El propio archivo aclara que auth.service.js no habla con google-auth-library de forma directa.
Este módulo también incluye dos hooks de prueba. En NODE_ENV === 'test', los tests pueden sustituir el verificador completo por una implementación determinista. Eso evita depender de llamadas reales a Google durante la ejecución de pruebas. fileciteturn0file0turn0file7
[!NOTE] Si
env.googleClientIdno existe, la verificación no se ejecuta. El módulo responde con503y el códigoGOOGLE_AUTH_NOT_CONFIGURED.
How it works
flowchart TD
A[verifyGoogleIdToken] --> B{verifierOverride existe}
B -->|si| C[verifierOverride]
B -->|no| D{env googleClientId disponible}
D -->|no| E[ApiError 503 GOOGLE_AUTH_NOT_CONFIGURED]
D -->|si| F[OAuth2Client verifyIdToken]
F -->|falla| G[ApiError 401 GOOGLE_TOKEN_INVALID]
F --> H{payload tiene sub y email}
H -->|no| G
H -->|si| I[Normaliza sub email emailVerified givenName familyName name issuedAt]
C --> I
El flujo comienza con verifyGoogleIdToken(credential). Si existe verifierOverride, el módulo lo usa y devuelve su resultado directamente. Si no hay override, el módulo exige env.googleClientId y luego llama a OAuth2Client.verifyIdToken con idToken y audience. Después extrae el payload, valida sub y email, y devuelve solo los campos permitidos y normalizados.
[!IMPORTANT] El módulo nunca expone el mensaje crudo de
google-auth-library. Ante cualquier fallo de verificación, devuelve unApiErrorgenérico con401yGOOGLE_TOKEN_INVALID.
Key components
{
"title": "verifyGoogleIdToken",
"content": "Funci\u00f3n p\u00fablica que verifica un ID token de Google, valida la audiencia contra env.googleClientId y devuelve un perfil normalizado con los campos permitidos.",
"type": "function",
"filePath": "services/api/src/modules/auth/google-identity.client.js",
"badges": [
"public"
]
}
{
"title": "setGoogleIdentityVerifierForTests",
"content": "Funci\u00f3n p\u00fablica para pruebas que sustituye el verificador real por una implementaci\u00f3n determinista. Solo est\u00e1 disponible en NODE_ENV test.",
"type": "function",
"filePath": "services/api/src/modules/auth/google-identity.client.js",
"badges": [
"public"
]
}
{
"title": "resetGoogleIdentityVerifierForTests",
"content": "Funci\u00f3n p\u00fablica para pruebas que elimina el override del verificador cuando el entorno es test.",
"type": "function",
"filePath": "services/api/src/modules/auth/google-identity.client.js",
"badges": [
"public"
]
}
{
"title": "OAuth2Client cacheado",
"content": "Instancia interna creada bajo demanda por getClient y reutilizada entre llamadas para evitar recrear el cliente en cada verificaci\u00f3n.",
"type": "function",
"filePath": "services/api/src/modules/auth/google-identity.client.js",
"badges": [
"read-only"
]
}
Data & fields
[
{
"name": "credential",
"type": "string",
"required": true,
"description": "ID token de Google Identity Services recibido desde el frontend."
},
{
"name": "sub",
"type": "string",
"required": true,
"description": "Identificador estable del sujeto autenticado en Google."
},
{
"name": "email",
"type": "string",
"required": true,
"description": "Correo normalizado a minúsculas y sin espacios extremos."
},
{
"name": "emailVerified",
"type": "boolean",
"description": "Marca si Google indicó email_verified como true."
},
{
"name": "givenName",
"type": "string",
"description": "Nombre dado del perfil de Google, o cadena vacía si falta."
},
{
"name": "familyName",
"type": "string",
"description": "Apellido del perfil de Google, o cadena vacía si falta."
},
{
"name": "name",
"type": "string",
"description": "Nombre completo del perfil de Google, o cadena vacía si falta."
},
{
"name": "issuedAt",
"type": "number | null",
"description": "Marca temporal iat convertida a número, o null cuando no existe o no es válida."
}
]
El objeto retornado por verifyGoogleIdToken incluye únicamente esos campos. El archivo documenta explícitamente que no persiste el credential crudo ni el payload completo. El consumidor esperado, auth.service.js, solo lee sub, email, email_verified, given_name, family_name y name.
Behaviors
getClient— CreaOAuth2Clientde forma perezosa y devuelve la misma instancia en llamadas posteriores.setGoogleIdentityVerifierForTests(verifier)— Registra un verificador alternativo solo en tests. Si no está enNODE_ENV === 'test', lanza unError.resetGoogleIdentityVerifierForTests()— Limpia el override del verificador cuando el entorno es test.verifyGoogleIdToken(credential)— Verifica el token, aplica la audiencia configurada, valida el payload y devuelve un perfil normalizado. También transforma errores de verificación enApiErrorcontrolados. fileciteturn0file0turn0file7
Workflows
1. Recibir credential | El frontend entrega el ID token de Google al backend.
2. Resolver verificador | Si existe un override de test, se usa primero.
3. Comprobar configuración | Si falta `env.googleClientId`, el módulo responde con 503.
4. Verificar token | `OAuth2Client.verifyIdToken` valida firma, expiración, issuer y audiencia.
5. Validar payload | El módulo exige `sub` y `email`.
6. Normalizar salida | Devuelve solo los campos permitidos y formateados.
Este flujo encaja con el patrón descrito en el propio archivo: auth.service.js delega aquí la verificación técnica del token y trabaja después con un perfil reducido. El comentario del módulo también indica que el credential llega desde el callback de google.accounts.id.initialize en el frontend.
Gotchas & edge cases
[!WARNING]
setGoogleIdentityVerifierForTestssolo funciona en pruebas. En otros entornos lanzaErrorcon el mensajeGoogle identity verifier overrides are only available in tests.
[!WARNING] Si
OAuth2Client.verifyIdTokenfalla, el módulo no reexpone el error original. Siempre transforma ese fallo en401conGOOGLE_TOKEN_INVALID.
[!WARNING] Un payload sin
subo sinApiErrorde autenticación inválida o expirada. fileciteturn0file0turn0file7
[!CAUTION] El archivo asume que
env.googleClientIdya está definido para entornos donde Google Login debe funcionar. Si no está presente, el flujo queda indisponible por diseño del módulo.
Related
Este archivo conecta con services/api/src/modules/auth/auth.service.js, que consume el resultado de la verificación y no importa google-auth-library directamente. El comentario del módulo también lo relaciona con notification.client.js y notification.service.js como ejemplo del mismo patrón de capa de proveedor separada del dominio.
En el frontend, la identidad de Google se obtiene desde el callback de google.accounts.id.initialize, y el backend solo recibe el credential para verificarlo aquí. Los tests del repositorio usan setGoogleIdentityVerifierForTests y resetGoogleIdentityVerifierForTests para evitar llamadas reales a Google. fileciteturn0file0turn0file2