SECURITY 15 min

Autenticación vs. Autorización: Guía Completa de OAuth 2.1, OIDC, Passkeys y Zero Trust

Diferencias clave entre AuthN y AuthZ en arquitecturas modernas: OAuth 2.1, OpenID Connect (OIDC), autenticación sin contraseñas con Passkeys/WebAuthn, y gestión segura de tokens JWT sin estado frente a cookies HttpOnly.

Escrito por Samir El Azem Crovetto • Senior Backend Engineer & DevSecOps

El Problema de Confundir Identidad con Permisos

En la arquitectura de sistemas distribuidos y aplicaciones web empresariales, una de las fuentes más recurrentes de vulnerabilidades críticas es la confusión conceptual y técnica entre Autenticación (AuthN) y Autorización (AuthZ).

No se trata de un debate semántico para manuales académicos: mezclar quién es el usuario con qué tiene permitido hacer conduce inevitablemente a brechas severas como la Asignación Insegura de Roles, la Referencia Directa Insegura a Objetos (IDOR / BOLA) y la Escalada de Privilegios Horizontal y Vertical.

En 2026, los mecanismos de seguridad han madurado drásticamente: los protocolos heredados (como el flujo implícito de OAuth 2.0 o el almacenamiento de tokens JWT en el localStorage del navegador) se consideran antipatrones peligrosos. La industria ha convergido hacia OAuth 2.1, OpenID Connect (OIDC) federado, autenticación biométrica sin contraseñas (Passkeys / WebAuthn) y el patrón Backend-For-Frontend (BFF).

En este artículo analizamos en profundidad la arquitectura moderna de AuthN y AuthZ: cómo diseñar sistemas tolerantes a fallos, cómo verificar criptográficamente tokens sin comprometer la latencia y cómo gobernar permisos bajo el paradigma Zero Trust.


Arquitectura Unificada: Flujo Moderno AuthN y AuthZ

Para evitar acoplar la gestión de credenciales con la lógica de negocio de los microservicios, la arquitectura empresarial moderna delega la identidad en un Proveedor de Identidad (IdP) centralizado y desacopla la autorización en la capa de API Gateway o en un motor de políticas (como OPA o Cedar).

El siguiente diagrama detalla el flujo de autenticación mediante Passkeys (WebAuthn), intercambio de tokens OAuth 2.1 con PKCE y verificación de permisos por atributos (ABAC):

flowchart TD
    subgraph Client_Layer ["Capa de Cliente (SPA / Mobile)"]
        A[Usuario / Navegador] -->|1. Desafio Biometrico WebAuthn| B[Passkey / Credencial FIDO2]
        B -->|2. Firma Criptografica| C[Peticion Auth OIDC con PKCE]
    end

    subgraph Identity_Provider ["Servidor de Autorizacion (IdP OIDC)"]
        C --> D[Verificacion de Clave Publica]
        D -->|3. Emision de Tokens Criptograficos| E[ID Token OIDC + Access Token JWT]
    end

    subgraph API_Perimeter ["Perimetro de Red (API Gateway / BFF)"]
        E -->|4. Peticion con Bearer Token| F[API Gateway / Reverse Proxy]
        F --> G[Validacion JWKS en Memoria<br/>Issuer, Audience, Expiracion]
    end

    subgraph Services_Layer ["Capa de Microservicios (Zero Trust)"]
        G -->|5. Contexto de Identidad Seguro| H[Servicio de Negocio]
        H --> I[Motor de Politicas AuthZ ABAC / RBAC<br/>Decision de Acceso Determinista]
        I --> J[Ejecucion Segura de la Operacion]
    end

    classDef stage fill:#1e1e2e,stroke:#6366f1,stroke-width:2px,color:#cdd6f4;
    class Client_Layer,Identity_Provider,API_Perimeter,Services_Layer stage;

1. AuthN vs. AuthZ: La Distinción Canónica

Establezcamos la separación estricta que todo equipo de ingeniería debe respetar:

Autenticación (AuthN - Authentication): "¿Quién eres?"

  • Objetivo: Verificar y probar matemáticamente la identidad declarada por un usuario, proceso o dispositivo.
  • Mecanismos: Claves criptográficas asimétricas (Passkeys), contraseñas robustas con KDF, tokens TOTP, certificados X.509 o identidad federada OIDC.
  • Artefacto emitido: En OIDC, la prueba de autenticación es el ID Token (un JWT diseñado específicamente para que el cliente conozca la identidad del usuario: sub, email, auth_time).

Autorización (AuthZ - Authorization): "¿Qué tienes permitido hacer?"

  • Objetivo: Determinar si una identidad previamente autenticada posee los privilegios necesarios para ejecutar una acción específica sobre un recurso determinado en un contexto dado.
  • Mecanismos: Control de Acceso Basado en Roles (RBAC), Control de Acceso Basado en Atributos (ABAC), listas de control de acceso (ACL) o políticas como código.
  • Artefacto emitido: En OAuth 2.1, el vehículo de autorización es el Access Token (destinado al servidor de recursos y APIs, nunca al usuario final).
Dimensión Autenticación (AuthN) Autorización (AuthZ)
Pregunta fundamental ¿Quién es el sujeto? ¿Tiene permiso para esta acción?
Punto de ejecución Al inicio de la sesión / IdP En cada endpoint o recurso protegido
Protocolo estándar OpenID Connect (OIDC), WebAuthn OAuth 2.1, Open Policy Agent (OPA)
Token representativo id_token access_token
Consecuencia de fallo Código HTTP 401 Unauthorized Código HTTP 403 Forbidden

2. La Evolución de la Sesión Web: De Cookies a JWT y el Patrón BFF

Durante años, la comunidad debatió intensamente: ¿Cookies de sesión con estado o tokens JWT sin estado?

El Dilema Tradicional:

  • Cookies de sesión clásicas: Almacenan el identificador en memoria o base de datos (ej. Redis). Son excelentes para revocación inmediata, pero penalizan la escalabilidad horizontal y son vulnerables a CSRF (Cross-Site Request Forgery) si no se configuran correctamente las directivas SameSite=Strict y tokens anti-CSRF.
  • JWTs puros en SPA: Guardar un JWT en localStorage o sessionStorage elimina la necesidad de consultar bases de datos en cada petición. Sin embargo, introduce un fallo crítico de seguridad: cualquier vulnerabilidad de Cross-Site Scripting (XSS) en la aplicación permite a un atacante robar el token y secuestrar la identidad.

La Solución Definitiva: El Patrón Backend-For-Frontend (BFF)

Una de las soluciones más sólidas y extendidas en la industria es el patrón BFF (Backend-For-Frontend):

  1. La aplicación Single Page (React/Vue) jamás toca directamente los tokens de acceso criptográficos ni los almacena en JavaScript.
  2. El cliente se comunica con su propio backend intermedio (BFF) utilizando cookies HTTP-Only, Secure y SameSite=Strict.
  3. El BFF gestiona de forma confidencial el intercambio de tokens OAuth 2.1 con el IdP, renueva los tokens mediante Refresh Tokens en un almacenamiento seguro del servidor y envía el JWT en la cabecera Authorization: Bearer exclusivamente en las llamadas internas entre microservicios.

3. OAuth 2.1: Depuraciones Críticas que Debes Aplicar Hoy

El estándar OAuth 2.1 consolida una década de lecciones operativas y elimina directivas obsoletas que dieron lugar a vulnerabilidades masivas:

  1. Eliminación Total del Implicit Grant: El flujo implícito (que devolvía tokens de acceso directamente en el fragmento de la URL #access_token=...) está terminantemente prohibido. Los tokens en la URL quedan registrados en el historial del navegador, en cabeceras Referer y en logs de proxies intermedios.
  2. Eliminación del Resource Owner Password Credentials Grant (ROPC): Prohibido solicitar las credenciales del usuario en la aplicación cliente para intercambiarlas por un token. El usuario debe autenticarse exclusivamente en el IdP.
  3. PKCE Obligatorio para Todos los Clientes: El mecanismo Proof Key for Code Exchange (PKCE) es obligatorio en todos los clientes, incluidos los confidenciales. Previene ataques de interceptación del código de autorización mediante un desafío criptográfico (codeverifier y codechallenge).
  4. Coincidencia Exacta de URIs de Redirección: Prohibido el uso de comodines (*) o coincidencia de subdominios en redirect_uri para neutralizar ataques de redirección abierta.

4. Passkeys y WebAuthn: El Futuro Sin Contraseñas

Las contraseñas compartidas siguen siendo el vector más vulnerable de la seguridad digital. Passkeys, basadas en el estándar W3C / FIDO Alliance (WebAuthn), sustituyen contraseñas por pares de claves criptográficas asimétricas.

  • Resistencia Absoluta al Phishing: El navegador vincula criptográficamente el desafío de autenticación con el origen del dominio exacto (origin). Un sitio clonado en un dominio malicioso no puede obligar al autenticador local a firmar el desafío.
  • Cero Secretos en Base de Datos: El servidor solo almacena la clave pública del usuario. Si la base de datos se filtra íntegramente, ningún atacante puede utilizar los datos para suplantar identidades.

5. Implementación Práctica: Validación Segura de JWT con JWKS en Node.js/Express

El error más común al validar JWTs en microservicios es decodificar el payload sin verificar rigurosamente la firma criptográfica, o aceptar algoritmos no autorizados como alg: "none" (CVE-2015-9235).

A continuación se muestra una implementación de referencia en Node.js/TypeScript para validar tokens de acceso emitidos por un IdP moderno, verificando claves públicas rotativas mediante un endpoint JWKS (JSON Web Key Set):

// middleware/auth-validator.ts
import { Request, Response, NextFunction } from 'express';
import crypto from 'crypto';

interface JwksKey {
  kid: string;
  kty: string;
  alg: string;
  use: string;
  n: string;
  e: string;
}

interface JwtHeader {
  alg: string;
  kid: string;
  typ: string;
}

interface JwtPayload {
  iss: string;
  sub: string;
  aud: string;
  exp: number;
  nbf?: number;
  roles?: string[];
  [key: string]: any;
}

// Cache local en memoria de claves JWKS para evitar latencia
let jwksCache: Map<string, string> = new Map();
let lastJwksFetch = 0;
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hora

const EXPECTED_ISSUER = 'https://auth.secdevoops.ai.studio';
const EXPECTED_AUDIENCE = 'https://api.secdevoops.ai.studio';

/**
 * Convierte un componente RSA en formato Base64URL a PEM PublicKey
 */
function rsaPublicKeyToPem(nBase64: string, eBase64: string): string {
  const n = Buffer.from(nBase64, 'base64url');
  const e = Buffer.from(eBase64, 'base64url');
  
  const keyObject = crypto.createPublicKey({
    key: {
      kty: 'RSA',
      n: n.toString('base64'),
      e: e.toString('base64')
    },
    format: 'jwk'
  });
  
  return keyObject.export({ type: 'spki', format: 'pem' }) as string;
}

/**
 * Middleware de Validacion de Token con Verificacion Estricta Zero Trust
 */
export async function verifyAccessToken(req: Request, res: Response, next: NextFunction) {
  const authHeader = req.headers['authorization'];
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Falta cabecera de autorizacion Bearer' });
  }

  const token = authHeader.slice(7).trim();
  const parts = token.split('.');
  if (parts.length !== 3) {
    return res.status(401).json({ error: 'Estructura de JWT no valida' });
  }

  try {
    const [rawHeader, rawPayload, rawSignature] = parts;
    const header: JwtHeader = JSON.parse(Buffer.from(rawHeader, 'base64url').toString('utf8'));
    const payload: JwtPayload = JSON.parse(Buffer.from(rawPayload, 'base64url').toString('utf8'));

    // 1. Prohibir explicitamente algoritmos inseguros o none
    if (header.alg !== 'RS256' && header.alg !== 'EdDSA') {
      return res.status(401).json({ error: 'Algoritmo criptografico no admitido' });
    }

    // 2. Comprobar Issuer y Audience (Prevencion de Token Confusion)
    if (payload.iss !== EXPECTED_ISSUER) {
      return res.status(401).json({ error: 'Emisor del token (iss) invalido' });
    }
    if (payload.aud !== EXPECTED_AUDIENCE) {
      return res.status(401).json({ error: 'Destinatario del token (aud) invalido' });
    }

    // 3. Comprobar expiracion con tolerancia maxima de 60s para clock skew
    const now = Math.floor(Date.now() / 1000);
    if (payload.exp < now - 60) {
      return res.status(401).json({ error: 'El token ha expirado' });
    }

    // 4. Verificacion de la Firma Criptografica mediante clave publica
    const publicKeyPem = jwksCache.get(header.kid);
    if (!publicKeyPem) {
      return res.status(401).json({ error: 'Clave publica de firma no encontrada o no autorizada' });
    }

    const verifier = crypto.createVerify('RSA-SHA256');
    verifier.update(`${rawHeader}.${rawPayload}`);
    const isSignatureValid = verifier.verify(
      publicKeyPem,
      Buffer.from(rawSignature, 'base64url')
    );

    if (!isSignatureValid) {
      return res.status(401).json({ error: 'Firma criptografica de token invalida' });
    }

    // Inyectar contexto de identidad validado en el objeto de peticion
    (req as any).user = payload;
    next();
  } catch (err) {
    return res.status(401).json({ error: 'Fallo critico al procesar credenciales de acceso' });
  }
}

6. Autorización a Escala: De RBAC a ABAC y Zero Trust

Autenticar al usuario es solo el 50% de la ecuación. Una vez que el middleware inyecta req.user, el sistema debe evaluar si esa identidad puede operar sobre el recurso solicitado.

Limitaciones de RBAC Tradicional:

El control basado en roles simple (if (user.role === 'ADMIN')) colapsa rápidamente:

  • Proliferación caótica de roles: Terminas creando roles como BILLINGADMINEUROPE, EDITORDRAFTONLY.
  • Incapacidad de evaluar relaciones: RBAC no puede responder a: ¿Puede el usuario editar este documento si es el autor original y el documento no está archivado?

El Enfoque ABAC (Attribute-Based Access Control):

La autorización moderna evalúa cuatro dimensiones dinámicas:

  1. Sujeto: Quién realiza la petición (roles, departamento, antigüedad).
  2. Acción: Qué operación intenta ejecutar (read, update, publish, delete).
  3. Recurso: Qué entidad es el objetivo (autor, clasificación de confidencialidad, estado).
  4. Entorno: Contexto de la llamada (dirección IP corporativa, hora laboral, nivel de riesgo del dispositivo).

Implementar esta evaluación de forma desacoplada mediante motores de políticas declarativos garantiza que los cambios de regulación o negocio no exijan reescribir código en los microservicios, como se detalla en nuestra guía de DevSecOps y Shift-Left en CI/CD y en las prácticas de Hardening de Servidores e Infraestructuras.


Conclusión

Diseñar sistemas web seguros en 2026 exige superar las soluciones improvisadas: adoptar OAuth 2.1 con PKCE, blindar los clientes con el patrón BFF, incorporar Passkeys para erradicar las contraseñas y aplicar validación estricta de tokens con arquitecturas Zero Trust.

Si necesitas auditar la seguridad de tus sistemas de autenticación, diseñar arquitecturas OAuth 2.1 federadas o evaluar vulnerabilidades de autorización en tus APIs, puedes consultar mis Servicios de Ciberseguridad y Consultoría o contactar directamente conmigo en Sobre mí.