Ir al contenido

Autenticación de Usuarios

Distinción Clave: OAuth 2.0 vs OpenID Connect (OIDC)

Sección titulada «Distinción Clave: OAuth 2.0 vs OpenID Connect (OIDC)»

Antes de implementar cualquier patrón, es vital entender la diferencia (la confusión más común en la industria):

  • OAuth 2.0 es para Autorización: Sirve para delegar acceso (ej. “Quiero que esta app lea mis correos”). Emite un access_token (opaco para el cliente). No sirve para autenticar al usuario.
  • OpenID Connect (OIDC) es para Autenticación: Es una capa construida sobre OAuth 2.0. Emite un id_token (un JWT) que contiene información firmada sobre quién es el usuario (nombre, email).

Regla de Oro HERA: Si necesitas saber quién es el usuario para iniciar una sesión en tu app, debes usar OIDC, validando el id_token.


No todas las aplicaciones necesitan el mismo patrón de autenticación. Utiliza este árbol para elegir el camino correcto antes de iniciar el desarrollo.

Árbol de Decisión Canónico — Autenticación en HERA
Cómo elegir el patrón de autenticación correcto según la audiencia y el tipo de aplicación.
¿La aplicación es para usuarios internos (empleados Grupo Herdez)?
¿Está expuesta a través de un Load Balancer (Ingress)?
1. IAP (Identity-Aware Proxy) El estándar por defecto. Zero-code auth.
NO (App interna)
2. OIDC Manual con Google Workspace Validación de JWT claims.
NO (Clientes / Partners Externos)
¿Necesita gestión completa de usuarios (registro, MFA, password reset)?
3. Identity Platform Requiere revisión de FinOps (costo por MAU).
NO
4. OAuth 2.0 / OIDC Manual Implementación estricta con PKCE.

1. Identity-Aware Proxy (IAP) — El Default Interno

Sección titulada «1. Identity-Aware Proxy (IAP) — El Default Interno»

IAP es el estándar de oro en HERA para cualquier aplicación diseñada para empleados o colaboradores internos (Google Workspace). Actúa como un proxy de identidad a nivel del balanceador de carga.

  • Cuándo: Aplicaciones web internas expuestas a través de un Global External HTTPS Load Balancer (GCLB).
  • Cómo: Se habilita en la consola de GCP o vía Terraform en el servicio backend. No requiere SDKs en tu código.
  • Validación: El backend solo necesita validar el header criptográfico X-Goog-IAP-JWT-Assertion para confirmar la identidad, asegurando que el request pasó legítimamente por el proxy.

2. Identity Platform — Gestión Completa Externa

Sección titulada «2. Identity Platform — Gestión Completa Externa»

Identity Platform es el servicio gestionado de Google (Customer Identity and Access Management - CIAM) para aplicaciones orientadas al consumidor (B2C) o partners externos.

  • Cuándo: Tu aplicación requiere registro de usuarios, recuperación de contraseñas, validación por email/SMS, autenticación biométrica o MFA de múltiples factores para usuarios fuera de Grupo Herdez.
  • Cómo: Se utilizan los SDKs de Firebase Authentication (Identity Platform es el motor enterprise de Firebase Auth).

Si por restricciones de negocio no puedes usar IAP ni Identity Platform, y debes integrar un proveedor social o un IdP corporativo B2B externo, debes implementar el flujo de Authorization Code con PKCE (Proof Key for Code Exchange).

Queda estrictamente prohibido el uso del Implicit Flow o retornar tokens directamente en la URL.

Flujo OIDC: Authorization Code con PKCE
El estándar de facto para autenticación web y móvil (sin usar Client Secret en el front).
1. Aplicación (Cliente)
Genera `code_verifier` y `code_challenge`. Redirige al IdP.
GET /auth?response_type=code&code_challenge=xyz...
↓ Redirección del Navegador
2. Identity Provider (IdP)
Autentica al usuario (login, MFA). Guarda el `code_challenge`.
Retorna `code` temporal al redirect_uri
↓ Redirección con Authorization Code (`code`)
3. Aplicación (Backend)
Envía el `code` y el `code_verifier` (el texto original en claro) al IdP por canal seguro (server-to-server).
POST /token { code: "abc", code_verifier: "text-original" }
↓ Intercambio Seguro (Server-to-Server)
4. Identity Provider (IdP)
El IdP aplica hash al `code_verifier` y lo compara con el `code_challenge` guardado en el paso 2. Si coinciden, retorna los tokens.
200 OK { access_token, id_token, refresh_token }
↓ Validación de JWT local
5. Aplicación (Backend)
Valida la firma criptográfica del `id_token`. Crea una sesión segura local (Cookie HttpOnly) para el navegador.

Los parámetros state, nonce y code_verifier deben ser generados criptográficamente.

// Ejemplo en Node.js (Crypto nativo)
const crypto = require('crypto');
// # simplificado para ilustración - En producción, encapsular en un módulo core
function generateOidcParameters() {
const codeVerifier = crypto.randomBytes(32).toString('base64url');
// PKCE Challenge (S256)
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
const state = crypto.randomBytes(16).toString('hex');
const nonce = crypto.randomBytes(16).toString('hex');
return { codeVerifier, codeChallenge, state, nonce };
}

Python (secrets + hashlib)

import secrets
import hashlib
import base64
def generate_oidc_parameters():
code_verifier = secrets.token_urlsafe(32)
# PKCE Challenge (S256)
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b"=").decode()
state = secrets.token_hex(16)
nonce = secrets.token_hex(16)
return {
"code_verifier": code_verifier,
"code_challenge": code_challenge,
"state": state,
"nonce": nonce,
}

Las 8 Validaciones Obligatorias del id_token

Sección titulada «Las 8 Validaciones Obligatorias del id_token»

Cuando el backend intercambia el code por los tokens de forma segura (Server-to-Server), debe validar criptográficamente el id_token recibido antes de confiar en él:

  1. Firma criptográfica: Validar la firma usando las claves públicas del IdP (JWKS).
  2. Issuer (iss): Confirmar que el emisor es exactamente el IdP esperado.
  3. Audience (aud): Confirmar que tu aplicación (Client ID) es el destinatario previsto.
  4. Expiración (exp): Rechazar tokens caducados.
  5. Not Before (nbf / iat): El token no puede usarse antes de su emisión.
  6. Nonce (nonce): Debe coincidir con el generado en la Fase 1 para mitigar ataques de repetición.
  7. Dominio corporativo (hd): Si es un login interno, validar que el claim hd (Hosted Domain) es grupoherdez.com.mx.
  8. Email verificado (email_verified): Garantizar que el IdP verificó la propiedad del correo.

El id_token y el access_token no deben ser enviados al navegador para almacenamiento en localStorage.

  1. El backend valida el id_token.
  2. El backend crea una sesión local (en base de datos o Redis).
  3. El backend envía una Cookie de sesión opaca, HttpOnly, Secure y SameSite=Lax/Strict al navegador.

El endpoint del backend que recibe el redirect (/auth/callback) es un vector crítico. Protege esta ruta:

  • Implementa Rate Limiting estricto en el WAF (Cloud Armor).
  • Valida que el parámetro state recibido coincida exactamente con el guardado en la cookie (encriptada) de la sesión previa.
  • Maneja correctamente los errores del IdP (error=access_denied) sin filtrar información interna.


Antes de aprobar un Merge Request que implemente autenticación manual (OIDC), el Tech Lead debe validar mecánicamente:

  • Se utiliza Authorization Code Flow con PKCE (nunca Implicit).
  • Los parámetros state, nonce y code_verifier se generan con un CSPRNG.
  • El intercambio del code por tokens se realiza Server-to-Server.
  • El backend valida obligatoriamente la firma, iss, aud, exp y nonce del id_token.
  • Si aplica, el backend valida el claim hd (Hosted Domain) para restringir el acceso corporativo.
  • La sesión se maneja mediante Cookies HttpOnly, Secure y SameSite.
  • El client_secret de OIDC se consume vía variable de entorno inyectada desde Secret Manager (cero credenciales en código).
  • Los scopes solicitados son estrictamente los mínimos necesarios (Incremental Authorization).
  • La comunicación del backend con APIs de Google utiliza Workload Identity (sin claves JSON).