Audiencia
Esta guía es para cualquier persona que necesite entender OAuth 2.0 y OpenID Connect conceptualmente:
- Desarrolladores backend implementando autenticación y autorización en APIs
- Desarrolladores frontend integrando botones de “Iniciar sesión con Google/GitHub/etc.”
- Ingenieros de seguridad revisando implementaciones de OAuth en busca de vulnerabilidades
- Arquitectos técnicos eligiendo entre estrategias de autenticación
- Product managers entendiendo SSO e integraciones con terceros
Un entendimiento básico de HTTP y APIs es útil pero no requerido. Construiremos desde los principios fundamentales.
Objetivo
Después de leer esta guía, entenderás:
- Qué problema resuelve OAuth 2.0 (y qué no resuelve)
- Los cuatro roles en cada interacción OAuth
- Cómo funcionan los flujos principales de OAuth (Authorization Code, Client Credentials)
- Por qué existe PKCE y contra qué protege
- La diferencia entre OAuth 2.0 y OpenID Connect
- Cuándo usar ID tokens vs. access tokens
- Cómo elegir el flujo correcto para tu aplicación
No estarás listo para implementar OAuth de forma segura (eso requiere un estudio más profundo), pero tendrás un modelo mental claro de cómo encaja todo.
1. El Problema que Resuelve OAuth
Imagina que estás construyendo un servicio de impresión de fotos. Los usuarios quieren imprimir fotos de su Google Drive. La solución ingenua: pedir a los usuarios su contraseña de Google.
Esto es terrible por múltiples razones:
- Confianza: Los usuarios deben confiar en ti con sus credenciales de Google
- Alcance del acceso: Obtienes acceso completo a su cuenta de Google, no solo a las fotos
- Revocación: Si los usuarios quieren dejar de usar tu servicio, deben cambiar su contraseña de Google
- Seguridad: Ahora almacenas contraseñas de cuentas que no son tuyas
OAuth resuelve esto habilitando la autorización delegada:
“Permite que los usuarios otorguen a tu aplicación acceso limitado a sus recursos en otro servicio, sin compartir sus credenciales.”
graph LR
A[App de Impresión] -->|"¿Puedo acceder a
las fotos de Alice?"| B[Google]
B -->|"Alice, ¿apruebas
esto?"| C[Alice]
C -->|"Sí, solo
leer fotos"| B
B -->|"Aquí tienes un token
solo para fotos"| A
style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e9Insight clave: OAuth trata sobre autorización (qué puedes hacer), no sobre autenticación (quién eres).
Lo que OAuth NO es
OAuth no te dice:
- Quién es el usuario
- El email o nombre del usuario
- Si el usuario ha iniciado sesión en su cuenta
OAuth solo te dice: “Este token otorga acceso a estos recursos específicos.”
Esta distinción importa. Veremos cómo OpenID Connect añade identidad más adelante.
2. Los Cuatro Roles
Cada interacción OAuth involucra cuatro roles distintos. Entenderlos es esencial.
graph TB
subgraph "Los Cuatro Roles de OAuth"
RO[Resource Owner
El usuario dueño de los datos]
C[Client
Tu aplicación]
AS[Authorization Server
Emite tokens]
RS[Resource Server
Aloja los datos protegidos]
end
RO -->|"Otorga permiso"| C
C -->|"Solicita token"| AS
AS -->|"Emite token"| C
C -->|"Presenta token"| RS
RS -->|"Devuelve datos"| C
style RO fill:#e8f5e9
style C fill:#e3f2fd
style AS fill:#fff3e0
style RS fill:#fce4ecResource Owner (Propietario del Recurso)
El Resource Owner es el usuario que posee los datos protegidos. En nuestro ejemplo de impresión de fotos, es la persona cuyas fotos de Google Drive quieres acceder.
El resource owner puede otorgar o denegar acceso a sus recursos. Es la autoridad final.
Client (Cliente)
El Client es tu aplicación—el software que quiere acceder a los datos del resource owner. Puede ser:
- Una aplicación web
- Una app móvil
- Una aplicación de escritorio
- Un servicio backend
Importante: En terminología OAuth, “client” significa tu aplicación, no el usuario final.
Authorization Server (Servidor de Autorización)
El Authorization Server autentica al resource owner y emite access tokens al client. Es el guardián.
Ejemplos:
- Servidor OAuth de Google (
accounts.google.com) - Servidor OAuth de GitHub (
github.com/login/oauth) - El proveedor de identidad de tu empresa
El authorization server maneja:
- Autenticación del usuario (login)
- Pantallas de consentimiento ("¿Permitir a esta app…?")
- Emisión de tokens
- Validación de tokens (a veces)
Resource Server (Servidor de Recursos)
El Resource Server aloja los recursos protegidos y acepta access tokens. Es donde viven los datos.
Ejemplos:
- API de Google Drive
- API de GitHub
- API interna de tu empresa
En muchos sistemas, el authorization server y el resource server son el mismo (o son operados por la misma organización). Pero conceptualmente, son roles separados.
Resumen de Roles
| Rol | Pregunta que Responde | Ejemplo |
|---|---|---|
| Resource Owner | ¿De quién son los datos? | Alice (la usuaria) |
| Client | ¿Qué app quiere acceso? | Servicio de Impresión de Fotos |
| Authorization Server | ¿Quién emite tokens? | Google OAuth |
| Resource Server | ¿Dónde están los datos? | API de Google Drive |
3. Flujo Authorization Code
El Flujo Authorization Code es el flujo OAuth más común y seguro. Se usa cuando tu aplicación tiene un servidor backend que puede almacenar secretos de forma segura.
Cuándo Usarlo
- Aplicaciones web con un componente del lado del servidor
- Apps móviles (con PKCE—más sobre esto después)
- Cualquier escenario donde el client puede mantener un secreto
El Flujo Paso a Paso
sequenceDiagram
participant U as Usuario (Navegador)
participant C as Client (Tu App)
participant AS as Authorization Server
participant RS as Resource Server
U->>C: 1. Click "Iniciar sesión con Google"
C->>U: 2. Redirigir a Google
U->>AS: 3. Usuario se autentica y da consentimiento
AS->>U: 4. Redirigir de vuelta con código de auth
U->>C: 5. Enviar código de auth al backend
C->>AS: 6. Intercambiar código por tokens
AS->>C: 7. Devolver access token (y refresh token)
C->>RS: 8. Solicitar datos con access token
RS->>C: 9. Devolver datos protegidosVamos paso a paso:
Pasos 1-2: Iniciar el flujo
El usuario hace click en “Iniciar sesión con Google” en tu app. Tu app lo redirige al endpoint de autorización de Google:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code
&client_id=TU_CLIENT_ID
&redirect_uri=https://tuapp.com/callback
&scope=https://www.googleapis.com/auth/drive.readonly
&state=xyz123
Parámetros clave:
response_type=code: Queremos un código de autorizaciónclient_id: El identificador de tu app (registrado con Google)redirect_uri: A dónde enviar al usuario después de la autorizaciónscope: Qué permisos estás solicitandostate: Valor aleatorio para prevenir ataques CSRF
Paso 3: El usuario se autentica y da consentimiento
Google muestra una pantalla de login (si es necesario) y una pantalla de consentimiento:
“Servicio de Impresión de Fotos quiere:
- Ver tus archivos de Google Drive
Permitir / Denegar”
Pasos 4-5: Se devuelve el código de autorización
Si el usuario aprueba, Google redirige de vuelta a tu redirect_uri:
https://tuapp.com/callback?
code=4/0AX4XfWh...
&state=xyz123
El code es el código de autorización—un token de corta duración y un solo uso.
Pasos 6-7: Intercambiar código por tokens
Tu servidor backend (¡no el navegador!) intercambia el código por tokens:
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=4/0AX4XfWh...
&redirect_uri=https://tuapp.com/callback
&client_id=TU_CLIENT_ID
&client_secret=TU_CLIENT_SECRET
Google responde con:
{
"access_token": "ya29.a0AfH6SM...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "1//0g..."
}
Pasos 8-9: Acceder a recursos protegidos
Tu app usa el access token para llamar a la API de Google:
GET /drive/v3/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ya29.a0AfH6SM...
¿Por Qué el Paso Extra?
¿Por qué no devolver el access token directamente? ¿Por qué el intercambio de código?
Seguridad. El código de autorización pasa por el navegador del usuario (en la URL). Si devolviéramos el access token ahí:
- Sería visible en el historial del navegador
- Podría ser registrado por proxies
- Extensiones maliciosas del navegador podrían robarlo
Al requerir un intercambio en el backend con el client_secret, aseguramos:
- Solo tu servidor puede obtener el access token
- El token nunca toca el navegador
- Incluso si alguien roba el código, no puede usarlo sin tu secreto
4. Flujo Client Credentials
El Flujo Client Credentials es más simple—es para comunicación máquina a máquina donde no hay un usuario involucrado.
Cuándo Usarlo
- Servicios backend llamando a otros servicios backend
- Trabajos programados accediendo a APIs
- Cualquier escenario donde no hay un usuario humano
El Flujo
sequenceDiagram
participant C as Client (Servicio Backend)
participant AS as Authorization Server
participant RS as Resource Server
C->>AS: 1. Solicitar token con credenciales del client
AS->>C: 2. Devolver access token
C->>RS: 3. Solicitar datos con access token
RS->>C: 4. Devolver datosPasos 1-2: Solicitar token
Tu servicio se autentica directamente con sus credenciales:
POST /token HTTP/1.1
Host: auth.ejemplo.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(client_id:client_secret)
grant_type=client_credentials
&scope=api.read api.write
Respuesta:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600
}
Pasos 3-4: Usar el token
Igual que antes—incluir el token en las peticiones a la API.
Sin Resource Owner
Nota que no hay usuario en este flujo. El client actúa en su propio nombre, no en nombre de un usuario. El access token representa los permisos del client, no los de un usuario.
Esto es apropiado para:
- Comunicación entre microservicios
- Trabajos de procesamiento por lotes
- Herramientas de administración
5. Flujo Implicit (Obsoleto)
Puede que encuentres el Flujo Implicit en documentación antigua. Fue diseñado para apps basadas en navegador que no podían almacenar secretos de forma segura.
graph LR
A[App en Navegador] -->|"Solicitud"| B[Auth Server]
B -->|"Token en fragmento de URL"| A
style A fill:#ffcdd2
style B fill:#ffcdd2Por qué está obsoleto:
- Access token expuesto en la URL del navegador
- Vulnerable a fugas de tokens
- Sin refresh tokens
- PKCE proporciona una mejor solución
No uses el Flujo Implicit para nuevas aplicaciones. Usa el Flujo Authorization Code con PKCE en su lugar.
6. PKCE Explicado
PKCE (Proof Key for Code Exchange, pronunciado “pixi”) es una extensión que hace que el Flujo Authorization Code sea seguro para clients públicos—aplicaciones que no pueden mantener un secreto.
El Problema que Resuelve PKCE
Las apps móviles y las aplicaciones de página única (SPAs) no pueden almacenar de forma segura un client_secret. Cualquiera puede:
- Descompilar una app móvil
- Ver el código fuente de JavaScript
Sin un secreto, ¿qué impide que un atacante intercepte el código de autorización y lo intercambie por tokens?
La Solución: Code Verifier y Challenge
PKCE añade un secreto dinámico para cada solicitud de autorización:
sequenceDiagram
participant C as Client
participant AS as Auth Server
Note over C: Genera un
code_verifier aleatorio
Note over C: Crea code_challenge
= SHA256(code_verifier)
C->>AS: 1. Solicitud de auth + code_challenge
Note over AS: Almacena code_challenge
AS->>C: 2. Devuelve código de autorización
C->>AS: 3. Solicitud de token + code_verifier
Note over AS: Verifica:
SHA256(code_verifier)
== challenge almacenado?
AS->>C: 4. Devuelve tokensCómo funciona:
El client genera un secreto (code_verifier): Una cadena aleatoria, ej.,
dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXkEl client crea un challenge:
code_challenge = BASE64URL(SHA256(code_verifier))La solicitud de autorización incluye el challenge:
https://auth.ejemplo.com/authorize?
response_type=code
&client_id=TU_CLIENT_ID
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
...
- El intercambio de token incluye el verifier original:
POST /token
grant_type=authorization_code
&code=CODIGO_AUTH
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
- El servidor verifica: SHA256(code_verifier) debe coincidir con el challenge almacenado
Por Qué Funciona
Incluso si un atacante intercepta el código de autorización:
- No tiene el
code_verifier - El challenge fue hasheado, así que no pueden revertirlo
- No pueden completar el intercambio de token
PKCE debería usarse para todos los flujos authorization code, no solo para clients públicos. Es una medida de defensa en profundidad.
7. OpenID Connect: Capa de Identidad
OAuth 2.0 responde: “¿Puede esta app acceder a estos recursos?”
Pero no responde: “¿Quién es el usuario?”
OpenID Connect (OIDC) es una capa sobre OAuth 2.0 que añade identidad. Responde: “¿Quién acaba de iniciar sesión?”
graph TB
subgraph "La Relación"
OAuth[OAuth 2.0
Autorización]
OIDC[OpenID Connect
Identidad + Autorización]
end
OAuth -->|"Construido encima de"| OIDC
style OAuth fill:#fff3e0
style OIDC fill:#e3f2fdQué Añade OIDC
- ID Token: Un JWT que contiene claims de identidad del usuario
- Endpoint UserInfo: Una API para obtener datos del perfil del usuario
- Scopes Estándar:
openid,profile,email - Claims Estándar:
sub,name,email,picture
Cuándo Usar OIDC
- “Iniciar sesión con Google/GitHub/Facebook”
- Single Sign-On (SSO)
- Cualquier momento que necesites saber QUIÉN es el usuario
Cuándo OAuth Simple es Suficiente
- Acceder a recursos del usuario (fotos, archivos, repositorios)
- Comunicación máquina a máquina
- Cualquier momento que solo necesites acceso, no identidad
8. ID Token vs. Access Token
OIDC introduce un nuevo tipo de token: el ID Token. Entender la diferencia entre ID tokens y access tokens es crucial.
Access Token
Propósito: Otorga acceso a recursos
Audiencia: Resource servers (APIs)
Contenido: Puede ser opaco (cadena aleatoria) o un JWT con claims de autorización
Ejemplo de uso:
GET /api/photos
Authorization: Bearer ya29.a0AfH6SM...
Quién lo valida: El resource server
ID Token
Propósito: Prueba la identidad del usuario
Audiencia: Tu aplicación (el client)
Contenido: Siempre un JWT con claims de identidad
Ejemplo decodificado:
{
"iss": "https://accounts.google.com",
"sub": "110169484474386276334",
"aud": "TU_CLIENT_ID",
"exp": 1704067200,
"iat": 1704063600,
"email": "[email protected]",
"name": "Alice Smith",
"picture": "https://lh3.googleusercontent.com/..."
}
Quién lo valida: Tu aplicación
Diferencias Clave
| Aspecto | Access Token | ID Token |
|---|---|---|
| Propósito | Acceder a recursos | Identificar al usuario |
| Audiencia | Resource server | Aplicación client |
| Formato | Opaco o JWT | Siempre JWT |
| Se envía a | APIs | Nunca se envía a APIs |
| Validez | Minutos a horas | Corta duración |
Error Común
Nunca envíes ID tokens a APIs como autorización.
Los ID tokens son para que tu aplicación sepa quién inició sesión. Los access tokens son para que las APIs autoricen peticiones.
# MAL - ID token a la API
GET /api/data
Authorization: Bearer eyJhbGciOiJSUzI1NiIs... (ID token)
# CORRECTO - Access token a la API
GET /api/data
Authorization: Bearer ya29.a0AfH6SM... (Access token)
9. Eligiendo el Flujo Correcto
Aquí hay un árbol de decisión para elegir el flujo OAuth correcto:
flowchart TD
A[Inicio] --> B{¿Hay un usuario?}
B -->|No| C[Flujo Client Credentials]
B -->|Sí| D{¿Tu app puede
mantener un secreto?}
D -->|Sí| E[Flujo Authorization Code]
D -->|No| F[Flujo Authorization Code
+ PKCE]
E --> G{¿Necesitas identidad?}
F --> G
G -->|Sí| H[Añadir OpenID Connect]
G -->|No| I[OAuth 2.0 simple]
style C fill:#fff3e0
style E fill:#e3f2fd
style F fill:#e8f5e9
style H fill:#fce4ecTabla Resumen
| Escenario | Flujo | ¿OIDC? |
|---|---|---|
| App web con backend | Authorization Code | Opcional |
| App de página única (SPA) | Authorization Code + PKCE | Generalmente sí |
| App móvil | Authorization Code + PKCE | Generalmente sí |
| Servicio backend | Client Credentials | No |
| Botón “Iniciar sesión con X” | Authorization Code (+ PKCE) | Sí |
Recomendaciones Modernas
- Siempre usa PKCE para flujos authorization code, incluso si tienes un backend
- Nunca uses el Flujo Implicit para nuevas aplicaciones
- Usa OIDC cuando necesites saber quién es el usuario
- Usa OAuth simple cuando solo necesites acceder a recursos
10. Qué Viene Después
Ahora entiendes la base conceptual de OAuth 2.0 y OpenID Connect. Sabes:
- Por qué existe OAuth (autorización delegada)
- Los cuatro roles (resource owner, client, authorization server, resource server)
- Cómo funcionan los flujos principales (authorization code, client credentials)
- Por qué existe PKCE (seguridad para clients públicos)
- La diferencia entre OAuth y OIDC (autorización vs. identidad)
- Cuándo usar ID tokens vs. access tokens
Lo que Esta Guía No Cubrió
Esta guía intencionalmente evitó:
- Detalles de implementación: Cómo implementar OAuth de forma segura en tu lenguaje/framework
- Vulnerabilidades comunes: CSRF, fugas de tokens, manipulación de redirect URI
- Almacenamiento de tokens: Dónde y cómo almacenar tokens de forma segura
- Rotación de refresh tokens: Manejar la expiración de tokens de forma segura
- Flujos avanzados: Device Authorization, Token Exchange
Estos temas requieren un estudio más profundo y práctica hands-on.
Próximos Pasos Recomendados
Aprendizaje práctico:
- Intenta implementar OAuth con un proveedor (Google, GitHub, Auth0)
- Usa una librería bien probada (nunca hagas tu propio OAuth)
- Estudia las especificaciones RFC (listadas abajo)
Vista Previa del Curso:
OAuth 2.0 Bien Hecho (y Mal Hecho)
Un curso práctico que cubre:
- Patrones de implementación seguros
- Escenarios de ataque del mundo real
- Estrategias de almacenamiento de tokens
- Errores de configuración comunes
- Depuración de flujos OAuth
Próximamente en API/OS
Términos del Vocabulario Relacionados
Profundiza tu comprensión explorando estos términos:
- OAuth 2.0 - El framework de autorización en detalle
- OpenID Connect - Especificación de la capa de identidad
- JWT - Formato de token usado por OIDC y muchas implementaciones OAuth
- Bearer Token - Cómo se transmiten los access tokens
- Authorization - Qué puedes hacer con los recursos
- Authentication - Probar quién eres
Estándares y RFCs
- RFC 6749 - OAuth 2.0 Authorization Framework
- RFC 6750 - Bearer Token Usage
- RFC 7636 - PKCE (Proof Key for Code Exchange)
- OpenID Connect Core 1.0 - Especificación de la capa de identidad
Has construido un modelo mental sólido de OAuth 2.0 y OpenID Connect. El siguiente paso es la implementación práctica—pero ahora entenderás qué estás implementando y por qué.