Un poco sobre Oauth2 y openID

Introducción

El ingreso a sitios o sistemas por medio de cookies y sesiones tiene algunos problemas. En términos de seguridad, son más difíciles de auditar o revocar. En cuanto al mantenimiento, por ejemplo en sistemas distribuidos, son difíciles de sincronizar: se necesitan añadir sticky sessions o alguna manera de compartir el almacenamiento de cookies, lo cual añade costo y complejidad. No quiero decir que no se deban usar, sino que escalarlos resulta más costoso y difícil.

En sistemas que necesitan escalabilidad generalmente se utiliza la extensión OpenID para la autenticación. OpenID funciona sobre el protocolo OAuth 2.0.

Menciono primero OpenID debido a que es un error común: OAuth 2.0 no fue hecho para la autenticación de usuarios. OAuth no es para crear sistemas de ingreso y registro de usuarios; en realidad fue hecho para compartir datos entre sistemas sin tener que intercambiar las claves de los usuarios entre ellos. Un buen ejemplo sería el registro en un software de contabilidad usando tu cuenta de Google o Facebook. En ese proceso te redirige a Google, ingresas, otorgas permisos para que ciertos datos (como el email) puedan ser usados por el software donde te registras. Google envía un código para que el sistema lo intercambie por un access token donde vendrá tu información.

Pero OAuth no solo se usa así. Como mencioné, el propósito principal de OAuth es intercambiar información de manera segura. Por eso en sistemas empresariales se utiliza muchísimo para integrar múltiples softwares: conectar tu cuenta a Stripe para recibir pagos, conectar a Salesforce para gestionar clientes o conectar a Gmail.

ya dejando claro que OpenID es una extensión para implementar autenticación y OAuth2 es un protocolo de autorización, podemos empezar a ver los detalles más técnicos.

Terminología de OAuth 2

  • resource owner: Usuario o servicio dueño de la información a la que otro sistema quiere acceder.
  • client: Sistema o servicio que quiere acceder a la información.
  • authorization server: Parte central de la autorización. Envía información de forma segura sin dar credenciales y es quien tiene el poder de otorgar permisos.
  • resource server: Servidor donde los datos del resource owner están almacenados (por ejemplo Google Contacts o Facebook Messages).
  • authorization grant: Prueba que la aplicación envía al authorization server indicando que el resource owner autorizó acceso.
  • redirect uri: URL a la que el authorization grant será enviado.
  • access token: Clave temporal que el sistema usa para acceder a la información del resource owner.

OAuth 2.0: Endpoints Principales

Authorization Endpoint

/authorize

Es el endpoint donde inicia el flujo. El cliente redirige al resource owner hacia este endpoint para solicitar permisos.

Aquí ocurre:

  • Autenticación del usuario (si aplica).
  • Consentimiento de permisos.
  • Generación del authorization code o del token (según el flujo).

Parámetros comunes:

  • response_type
  • client_id
  • redirect_uri
  • scope
  • state
  • code_challenge (si se usa PKCE)
  • code_challenge_method

Token Endpoint

/token

Es el endpoint donde se intercambia el authorization grant por un access token y opcionalmente por un refresh token.

Este endpoint también se usa para:

  • Obtener un nuevo access token usando un refresh token.
  • Flujos máquina-a-máquina (client credentials).
  • Flujos ROPC.

Parámetros comunes:

  • grant_type
  • code (si es authorization code)
  • refresh_token
  • client_id
  • client_secret (si aplica)
  • redirect_uri
  • code_verifier (PKCE)

Introspection Endpoint

/introspect

Se utiliza para validar opaque tokens.

Devuelve información estructurada sobre el token (si está activo, scopes, expiración, usuario, etc.).

Se usa ampliamente en sistemas empresariales con API Gateways.

Revocation Endpoint

/revoke

Permite revocar access tokens y refresh tokens, especialmente útil para sesiones de usuario y dispositivos.

Endpoints de OpenID Connect

UserInfo Endpoint

/userinfo

Devuelve información del usuario autenticado:

  • email
  • nombre
  • foto
  • claims adicionales

Requiere un access token válido, pero solo se usa en contextos OIDC.

Discovery Endpoint

/.well-known/openid-configuration

Proporciona un documento JSON con todos los endpoints, firmas, algoritmos y configuración del Authorization Server.

Es fundamental para clientes dinámicos y conexiones automáticas (como "Login with Google").

JWKS (JSON Web Key Set) Endpoint

/jwks.json

Publica claves públicas para verificar firmas de JWT.

Se usa cuando los access tokens o ID tokens son JWT firmados.

End Session Endpoint (Logout)

/logout o /session/end

Usado para cerrar sesiones.

Scopes en OpenID Connect

OIDC define scopes obligatorios y opcionales; estos pueden depender del provider (Keycloak, Okta, etc.).

Scopes obligatorios

  • openid → habilita OIDC; sin este scope, el flujo no es OIDC.

Scopes comunes

  • profile → nombre, apellido, avatar, género, fecha de nacimiento
  • email → email + verificación
  • phone → teléfono
  • address → dirección del usuario

Tokens específicos de OpenID Connect

OpenID añade un token adicional:

ID Token

Un JWT que contiene información de identidad del usuario.

Incluye claims como:

  • sub (identificador único del usuario)
  • email
  • email_verified
  • preferred_username
  • iss
  • aud
  • iat, exp
  • auth_time

El ID Token no es un access token. Su propósito es autenticación, no acceso a recursos.

Formas de Implementación

1. Cliente + Servidor

El resource owner es enviado al authorization server, donde puede dar permisos o iniciar sesión. Luego el authorization server redirige al cliente con el authorization grant. El cliente (desde el servidor) intercambia el código con el authorization server para obtener el access token.

Este método es el más seguro porque el código nunca se expone al navegador.

2. Cliente + Redirección + Cliente (obsoleto)

Este método fue deprecado. Aquí el authorization server enviaba el access token directamente al navegador, haciéndolo vulnerable a intercepciones. En OAuth 2.1 es obligatorio usar PKCE.

3. ROPC (Resource Owner Password Credentials)

El resource owner enviaba directamente sus credenciales al cliente, quien las enviaba al authorization server. El servidor devolvía el access token. Solo se usa en casos muy específicos, generalmente internos.

4. Máquina a Máquina (sin usuario)

El cliente (microservicio u otro servicio) se registra en el servidor de autorización y recibe un Client ID y un Client Secret. Con esas credenciales solicita un access token para acceder a los recursos.

Es el estándar para comunicarse entre microservicios o integraciones backend sin usuario humano.

Tokens

Existen tres tipos de tokens usados en OAuth2:

  • authorization grant: Código temporal (por ejemplo un UUID).
  • access token: Token usado para acceder a los recursos.
  • refresh token: Token usado para obtener nuevos access tokens sin repetir todo el flujo.

Además de JWT tokens para access tokens, existen opaque tokens, que son simplemente un string aleatorio que no contiene información.

Ventajas de opaque tokens:

  • Más pequeños.
  • Pueden ser revocados fácilmente.
  • Requieren validación mediante llamada al servidor.

Los JWT son ideales para arquitecturas de microservicios donde varios servicios necesitan validar tokens sin depender de un servidor central. Para sistemas con alta carga, los JWT suelen ser la mejor opción.

Las arquitecturas empresariales actuales no dependen de un solo tipo de token. Generalmente combinan ambas estrategias para maximizar seguridad y rendimiento.

Estrategias comunes

  1. Externo opaque + Interno JWT

El cliente obtiene un token opaco. El API Gateway lo valida por introspección y genera un JWT corto para los microservicios internos.

  1. Todo opaque

Access tokens de vida corta y refresh tokens de vida larga, ambos opacos.

  1. Access token JWT + Refresh token opaco

El access token es un JWT corto para rendimiento; el refresh opaco permite revocación controlada.

PKCE🧐

La implementación cliente + redirección + cliente se daba en el navegador, pero quedó obsoleta. Las Single web application tienen vulnerabilidades no pueden almacenar un client_secret y los tokens podían ser expuestos en la URL. por eso se creó PKCE (Proof Key for Code Exchange) la implementacion es la siguiente.

Proceso PKCE

  1. El cliente redirige al usuario al authorization server enviando un code_challenge.
  2. Tras autenticarse, el servidor redirige al cliente con el authorization code.
  3. El cliente envía una solicitud POST al servidor de tokens con el code_verifier.
  4. El servidor compara el hash del verificador con el desafío inicial.
  5. Si coinciden, entrega los tokens.

Por qué PKCE es seguro

Si un atacante intercepta el authorization code no podrá usarlo, porque no posee el code_verifier. No es posible generar un verificador válido a partir del challenge. PKCE es obligatorio para clientes públicos (como SPAs) en OAuth 2.1 y recomendado incluso para clientes con backend.