Audiencia
Esta guía es para desarrolladores que necesitan entender los fundamentos de seguridad en APIs:
- Desarrolladores backend implementando autenticación y autorización en APIs
- Desarrolladores frontend que necesitan manejar tokens y credenciales correctamente
- Diseñadores de APIs tomando decisiones sobre mecanismos de seguridad
- Cualquiera confundido sobre la diferencia entre 401 y 403, o por qué los tokens expiran
Deberías entender los conceptos básicos de HTTP. Si no, lee primero HTTP para APIs REST.
Objetivo
Después de leer esta guía, entenderás:
- La diferencia crítica entre autenticación y autorización
- Cuándo usar API keys, Basic auth o Bearer tokens
- Cómo funcionan los tokens: emisión, expiración, renovación y revocación
- Qué son los scopes y cómo limitan los permisos de los tokens
- Errores comunes que comprometen la seguridad de las APIs
- Cómo enviar credenciales correctamente en peticiones HTTP
Esta guía construye conciencia de seguridad—la base para proteger tus APIs.
1. Autenticación vs Autorización: La Distinción Fundamental
Estos dos conceptos se confunden frecuentemente, pero responden a preguntas completamente diferentes.
Autenticación: “¿Quién Eres?”
La autenticación prueba la identidad. Es el proceso de verificar que alguien es quien dice ser.
Piénsalo como mostrar tu DNI en la entrada de un edificio. El guardia comprueba tu foto, verifica que coincide con tu cara, y confirma que efectivamente eres esa persona.
flowchart LR
A[Cliente] -->|"Soy el usuario X
(credenciales)"| B[Servidor API]
B -->|"Verificar identidad"| C{¿Válido?}
C -->|Sí| D["Eres el usuario X
(autenticado)"]
C -->|No| E["401 Unauthorized"]
style D fill:#c8e6c9
style E fill:#ffccbcLa autenticación responde: “¿Es realmente Alice, o alguien pretendiendo ser Alice?”
Autorización: “¿Qué Puedes Hacer?”
La autorización comprueba permisos. Determina qué acciones puede realizar un usuario autenticado.
Continuando con la analogía del edificio: después de que el guardia confirme tu identidad, comprueba si tienes acceso al 5º piso. Puede que seas quien dices ser, pero eso no significa que puedas ir a todas partes.
flowchart LR
A[Usuario Autenticado] -->|"Acceder recurso X"| B[Servidor API]
B -->|"Comprobar permisos"| C{¿Permitido?}
C -->|Sí| D["200 OK
(acceso concedido)"]
C -->|No| E["403 Forbidden"]
style D fill:#c8e6c9
style E fill:#ffccbcLa autorización responde: “¿Puede Alice acceder a este recurso específico o realizar esta acción?”
Por Qué Importa la Distinción
Confundir esto lleva a vulnerabilidades de seguridad y manejo de errores confuso:
| Situación | Respuesta Correcta | Por Qué |
|---|---|---|
| Sin credenciales enviadas | 401 Unauthorized | Identidad no probada |
| Credenciales inválidas | 401 Unauthorized | Identidad no probada |
| Usuario válido, sin permiso | 403 Forbidden | Identidad probada, pero acceso denegado |
| Usuario válido, tiene permiso | 200 OK | Ambas comprobaciones pasaron |
flowchart TD
A[Petición a
recurso protegido] --> B{¿Credenciales
presentes?}
B -->|No| C[401 Unauthorized]
B -->|Sí| D{¿Credenciales
válidas?}
D -->|No| C
D -->|Sí| E{¿Tiene
permiso?}
E -->|No| F[403 Forbidden]
E -->|Sí| G[200 OK]
subgraph "Autenticación"
B
D
end
subgraph "Autorización"
E
end
style C fill:#ffccbc
style F fill:#fff3e0
style G fill:#c8e6c9Insight clave: La autenticación ocurre primero. No puedes comprobar permisos de alguien cuya identidad no has verificado.
2. API Keys: El Enfoque Simple
Las API keys son la forma más simple de autenticación de APIs. Son esencialmente cadenas largas y aleatorias que identifican un cliente.
Cómo Funcionan las API Keys
GET /api/weather?city=Madrid HTTP/1.1
Host: api.weather.com
X-API-Key: sk_live_a1b2c3d4e5f6g7h8i9j0
El servidor busca la clave, encuentra a qué cuenta pertenece, y procesa la petición en consecuencia.
Cuándo Usar API Keys
Las API keys funcionan bien para:
- Comunicación servidor a servidor donde la clave puede mantenerse secreta
- APIs públicas con rate limiting (identificar llamantes sin autenticación completa)
- Integraciones simples que no necesitan permisos a nivel de usuario
Limitaciones de las API Keys
Las API keys tienen limitaciones de seguridad significativas:
- Sin contexto de usuario: Una API key identifica una aplicación, no un usuario
- Difícil de revocar: Cambiar una clave afecta a todos los usuarios de esa aplicación
- Fácil de filtrar: A menudo acaban en código, logs o control de versiones
- Sin expiración por defecto: Las claves funcionan para siempre a menos que se revoquen manualmente
graph TD
A[API Key] --> B[Identifica Aplicación]
A --> C[Sin Contexto de Usuario]
A --> D[Larga duración]
A --> E[Acceso Binario]
B --> F["Bueno para: cuentas de servicio"]
C --> G["Malo para: datos específicos de usuario"]
D --> H["Riesgo: claves filtradas funcionan siempre"]
E --> I["Problema: no se puede limitar scope"]
style F fill:#c8e6c9
style G fill:#ffccbc
style H fill:#ffccbc
style I fill:#ffccbcDónde Enviar API Keys
Hay tres enfoques comunes:
Cabecera (recomendado):
GET /api/data HTTP/1.1
X-API-Key: tu_api_key_aqui
Parámetro de query (evitar si es posible):
GET /api/data?api_key=tu_api_key_aqui HTTP/1.1
¿Por qué evitar parámetros de query? Aparecen en:
- Logs del servidor
- Historial del navegador
- Cabeceras Referrer
- Logs de proxies
Esto hace que la filtración de claves sea mucho más probable.
3. Basic Authentication: El Método Integrado de HTTP
HTTP Basic authentication es un mecanismo estándar definido en RFC 7617. A pesar de su nombre, solo debería usarse con HTTPS.
Cómo Funciona Basic Auth
- El cliente envía usuario y contraseña, codificados en Base64
- El servidor decodifica y verifica las credenciales
- Cada petición incluye las credenciales (stateless)
GET /api/account HTTP/1.1
Host: api.example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
El valor codificado es username:password en Base64:
// Creando cabecera Basic auth
const credentials = btoa('username:password');
// Resultado: "dXNlcm5hbWU6cGFzc3dvcmQ="
Limitaciones de Basic Auth
Basic authentication tiene serios inconvenientes:
- Contraseña transmitida en cada petición: Incluso con HTTPS, esto aumenta la exposición
- Sin mecanismo de logout: Las credenciales se envían hasta que el cliente para
- Difícil de asegurar: Los usuarios deben confiar al cliente su contraseña real
- Sin expiración de token: La contraseña es válida hasta que se cambie
sequenceDiagram
participant C as Cliente
participant S as Servidor
C->>S: Petición (sin credenciales)
S->>C: 401 + WWW-Authenticate: Basic
Note over C: Usuario introduce contraseña
C->>S: Petición + Authorization: Basic ...
S->>C: 200 OK (autenticado)
Note over C,S: Contraseña enviada en CADA petición
C->>S: Otra petición + Authorization: Basic ...
S->>C: 200 OKCuándo Usar Basic Auth
Basic auth es aceptable para:
- Herramientas internas donde la simplicidad importa más que la seguridad
- Scripts y automatización usando cuentas de servicio
- Integración con sistemas legacy donde la auth moderna no está disponible
Nunca uses Basic auth para:
- Aplicaciones cara al usuario
- Apps móviles
- Cualquier escenario donde la contraseña pueda ser interceptada
4. Bearer Tokens: El Estándar Moderno
Los Bearer tokens son el estándar para autenticación moderna de APIs. El token “porta” la autenticación—quien lo tiene está autenticado.
Cómo Funcionan los Bearer Tokens
GET /api/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
El servidor valida el token y extrae información sobre la entidad autenticada.
¿Por Qué “Bearer”?
El nombre viene del concepto de que el portador del token (quien lo posee) obtiene acceso. Es similar a una entrada de concierto—quien la tenga, entra.
Implicación de seguridad: Los Bearer tokens deben protegerse como contraseñas. Cualquiera que obtenga el token tiene acceso.
Ventajas de los Bearer Tokens
| Ventaja | Explicación |
|---|---|
| Stateless | El servidor no necesita almacenar sesiones |
| Escalable | Cualquier servidor puede validar el token |
| Flexible | Puede contener info de usuario, permisos, expiración |
| Revocable | Puede invalidarse en el servidor |
| Tiempo limitado | Mecanismo de expiración incorporado |
Formatos Comunes de Tokens
Tokens opacos: Cadenas aleatorias que requieren consulta al servidor
Authorization: Bearer a7f8e9d0c1b2a3f4e5d6c7b8a9f0e1d2
JWT (JSON Web Tokens): Tokens auto-contenidos con datos embebidos
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Los JWTs se cubren en el término del vocabulario JWT. Son auto-verificables, lo que significa que el servidor puede validarlos sin una consulta a base de datos.
5. Ciclo de Vida del Token: De la Emisión a la Revocación
Entender el ciclo de vida del token es crucial para implementar autenticación segura.
Las Cuatro Etapas
flowchart LR
A[1. Emisión] --> B[2. Uso]
B --> C[3. Renovación]
C --> B
B --> D[4. Revocación]
C --> D
style A fill:#e3f2fd
style B fill:#c8e6c9
style C fill:#fff3e0
style D fill:#ffccbcEtapa 1: Emisión del Token
Los tokens se emiten tras autenticación exitosa:
sequenceDiagram
participant C as Cliente
participant A as Servidor Auth
C->>A: POST /oauth/token
Note right of C: usuario + contraseña
u otras credenciales
A->>A: Verificar credenciales
A->>A: Generar tokens
A->>C: 200 OK
Note left of A: access_token
refresh_token
expires_inEjemplo de respuesta:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"token_type": "Bearer",
"expires_in": 3600
}
Etapa 2: Uso del Token
El access token se envía con cada petición a la API:
GET /api/user/profile HTTP/1.1
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
El servidor valida:
- Firma del token (no manipulado)
- Expiración del token (no expirado)
- Claims del token (emisor, audiencia, etc.)
Etapa 3: Renovación del Token
Los access tokens tienen vida corta (minutos a horas). Los refresh tokens obtienen nuevos access tokens sin re-autenticación:
sequenceDiagram
participant C as Cliente
participant A as Servidor Auth
participant R as Servidor de Recursos
C->>R: Petición + access_token expirado
R->>C: 401 Token Expirado
C->>A: POST /oauth/token
Note right of C: grant_type=refresh_token
refresh_token=...
A->>A: Validar refresh token
A->>C: Nuevo access_token
C->>R: Petición + nuevo access_token
R->>C: 200 OKEtapa 4: Revocación del Token
Los tokens pueden invalidarse antes de expirar:
- Logout: El usuario termina la sesión explícitamente
- Cambio de contraseña: Todos los tokens invalidados
- Incidente de seguridad: Admin revoca todos los tokens
- Rotación de refresh token: Refresh token antiguo invalidado al emitir uno nuevo
POST /oauth/revoke HTTP/1.1
Content-Type: application/x-www-form-urlencoded
token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
&token_type_hint=access_token
Access Token vs Refresh Token
| Aspecto | Access Token | Refresh Token |
|---|---|---|
| Propósito | Acceder recursos | Obtener nuevos access tokens |
| Duración | Corta (15 min - 1 hora) | Larga (días - meses) |
| Se envía a | Servidores de recursos | Solo servidor de auth |
| Almacenamiento | Memoria (idealmente) | Almacenamiento seguro |
| Si es robado | Ventana de daño limitada | Brecha de seguridad mayor |
graph TD
subgraph "Corta duración"
AT[Access Token]
AT --> |"15 min - 1 hora"| ATU[Usado para llamadas API]
end
subgraph "Larga duración"
RT[Refresh Token]
RT --> |"Días - Meses"| RTU[Usado para obtener nuevos access tokens]
end
RT -.-> |"intercambia por"| AT
style AT fill:#c8e6c9
style RT fill:#fff3e0¿Por qué dos tokens? Si un access token es robado, el atacante tiene tiempo limitado. Los refresh tokens se envían menos frecuentemente (solo al servidor de auth) y pueden protegerse más estrictamente.
6. Scopes y Permisos
Los scopes definen qué puede hacer un token. Son el puente entre autenticación y autorización.
¿Qué Son los Scopes?
Los scopes son cadenas que representan permisos específicos:
read:users - Leer información de usuarios
write:users - Crear/actualizar usuarios
delete:users - Eliminar usuarios
admin:all - Acceso administrativo completo
Cómo Funcionan los Scopes
Al solicitar un token, el cliente especifica los scopes necesarios:
POST /oauth/authorize HTTP/1.1
Content-Type: application/x-www-form-urlencoded
client_id=mi_app
&redirect_uri=https://miapp.com/callback
&scope=read:users write:posts
&response_type=code
El token emitido contiene solo los scopes concedidos:
{
"access_token": "eyJ...",
"scope": "read:users write:posts",
"expires_in": 3600
}
La API aplica los scopes en cada petición:
flowchart TD
A[Petición: DELETE /users/123] --> B{¿Token válido?}
B -->|No| C[401 Unauthorized]
B -->|Sí| D{¿Tiene scope
'delete:users'?}
D -->|No| E[403 Forbidden]
D -->|Sí| F{¿Usuario tiene permiso
para este usuario?}
F -->|No| E
F -->|Sí| G[200 OK]
style C fill:#ffccbc
style E fill:#fff3e0
style G fill:#c8e6c9Patrones de Diseño de Scopes
Scopes basados en recursos:
users:read
users:write
posts:read
posts:write
Scopes basados en acciones:
read
write
delete
admin
Scopes de grano fino:
user.profile.read
user.profile.write
user.email.read
user.settings.write
El Principio de Mínimo Privilegio
Siempre solicita los scopes mínimos necesarios:
graph LR
subgraph "Mal: Sobre-permisionado"
B1[App solicita] --> B2[admin:all]
end
subgraph "Bien: Mínimo necesario"
G1[App solicita] --> G2[read:profile]
G1 --> G3[write:posts]
end
style B2 fill:#ffccbc
style G2 fill:#c8e6c9
style G3 fill:#c8e6c9Por qué importa:
- Limita el daño si el token es comprometido
- Hace la auditoría de autorización más fácil
- Los usuarios pueden tomar decisiones de consentimiento informadas
- Sigue las mejores prácticas de seguridad
7. Dónde Enviar Credenciales
La ubicación de las credenciales afecta la seguridad. No todos los métodos son iguales.
La Cabecera Authorization (Recomendado)
GET /api/data HTTP/1.1
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Ventajas:
- Diseñada específicamente para autenticación
- No se registra por defecto
- No contamina URLs
- Funciona con políticas de seguridad del navegador
Parámetros de Query (Evitar)
GET /api/data?access_token=eyJhbGciOiJIUzI1NiIs... HTTP/1.1
Problemas:
- Aparece en logs del servidor
- Se guarda en historial del navegador
- Visible en cabeceras referrer
- Puede ser cacheado por proxies
Solo aceptable para: URLs firmadas con expiración corta (como URLs pre-firmadas de S3).
Cuerpo de la Petición (A veces OK)
POST /api/data HTTP/1.1
Content-Type: application/json
{
"data": "...",
"access_token": "eyJhbGciOiJIUzI1NiIs..."
}
Aceptable para: Endpoints de intercambio de tokens (endpoint de token OAuth). Evitar para: Peticiones API regulares.
Cookies (Caso Especial)
GET /api/data HTTP/1.1
Cookie: session=abc123def456
Ventajas:
- Manejo automático por navegadores
- Pueden ser HttpOnly (no accesibles desde JavaScript)
- Pueden ser Secure (solo HTTPS)
Desventajas:
- Vulnerabilidades CSRF requieren protección adicional
- No funciona bien para clientes que no son navegadores
- Atadas a dominios
8. Errores Comunes de Seguridad
Estos errores comprometen la seguridad de las APIs. Aprende a reconocerlos y evitarlos.
Error 1: Tokens en URLs
# NUNCA hagas esto
GET /api/users?token=eyJhbGciOiJIUzI1NiIs... HTTP/1.1
Por qué es peligroso: Las URLs se registran en todas partes—logs del servidor, logs de proxies, historial del navegador, sistemas de analíticas. Tu token se filtrará.
Solución: Siempre usa la cabecera Authorization.
Error 2: Access Tokens de Larga Duración
{
"access_token": "...",
"expires_in": 31536000
}
Expiración de un año significa un año de acceso si el token es robado.
Solución: Access tokens de corta duración (15 minutos a 1 hora) con refresh tokens.
Error 3: Falta de HTTPS
# NUNCA envíes credenciales sobre HTTP
POST http://api.example.com/login HTTP/1.1
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Cualquiera en la red puede leer tus credenciales.
Solución: Siempre usa HTTPS. Sin excepciones.
Error 4: Almacenar Tokens en localStorage
// Peligroso: XSS puede robar esto
localStorage.setItem('token', accessToken);
Cualquier vulnerabilidad XSS en tu app puede robar todos los tokens almacenados.
Mejores enfoques:
- Solo memoria (para SPAs)
- Cookies HttpOnly (para apps web tradicionales)
- APIs de almacenamiento seguro (para apps móviles)
Error 5: No Validar Firmas de Token
// MAL: Solo decodifica, no verifica
const payload = jwt.decode(token);
user = payload.user; // ¡El atacante puede falsificar esto!
Solución: Siempre verifica la firma:
// CORRECTO: Verifica la firma
const payload = jwt.verify(token, secretKey);
user = payload.user; // Verificado
Error 6: Aceptar Cualquier Algoritmo
// PELIGROSO: El atacante puede usar algoritmo "none"
jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });
Solución: Lista blanca explícita de algoritmos permitidos:
// SEGURO: Solo HS256 aceptado
jwt.verify(token, secret, { algorithms: ['HS256'] });
9. Comparación de Métodos de Autenticación
Elige el método correcto para tu caso de uso:
graph TD
A[¿Necesitas autenticar?] --> B{¿Quién es el cliente?}
B -->|"Servidor/Servicio"| C{¿Necesita contexto de usuario?}
C -->|No| D[API Key]
C -->|Sí| E[OAuth Client Credentials]
B -->|"App de Navegador"| F{¿Tradicional o SPA?}
F -->|Tradicional| G[Cookie de Sesión]
F -->|SPA| H[Bearer Token + PKCE]
B -->|"App Móvil"| I[Bearer Token + PKCE]
B -->|"Script Simple"| J[API Key o Basic Auth]
style D fill:#e3f2fd
style E fill:#c8e6c9
style G fill:#fff3e0
style H fill:#c8e6c9
style I fill:#c8e6c9
style J fill:#e3f2fdMatriz de Decisión
| Método | Seguridad | Complejidad | Caso de Uso |
|---|---|---|---|
| API Key | Baja | Baja | Servidor a servidor, rate limiting |
| Basic Auth | Baja | Baja | Herramientas internas, scripts |
| Bearer Token | Alta | Media | Apps cara al usuario, APIs |
| OAuth 2.0 | Alta | Alta | Integración de terceros, acceso delegado |
| Cookie de Sesión | Media | Baja | Apps web tradicionales |
Qué Sigue
Esta guía cubrió autenticación y autorización a nivel conceptual—entendiendo qué son y por qué importan.
Para temas más profundos como:
- Implementar un sistema de permisos real
- Estrategias de rotación de tokens
- Manejar vulnerabilidades comunes de JWT
- Modelos de autorización complejos (RBAC, ABAC)
- Flujos de OAuth 2.0 en detalle
Ve el próximo curso: Autenticación y Autorización Robusta en APIs REST.
Términos Relacionados del Vocabulario
Profundiza tu comprensión:
- Autenticación - El proceso de verificar identidad
- Autorización - El proceso de comprobar permisos
- API Key - Mecanismo de autenticación simple
- Bearer Token - Estándar de autenticación basada en tokens
- JWT - JSON Web Tokens explicados
- OAuth 2.0 - Framework de autorización delegada
- Scopes - Límites de permisos para tokens