Clase 03 — Autenticación y Autorización en APIs
Autenticación vs Autorización
| Concepto | Pregunta | Ejemplo |
|---|---|---|
| Autenticación (AuthN) | ¿Quién sos? | Login con usuario/contraseña |
| Autorización (AuthZ) | ¿Qué podés hacer? | Admin puede borrar, viewer solo leer |
Métodos de autenticación
1. API Key
La forma más simple. Una clave estática que identifica a la aplicación.
# En header
curl -s -H "X-API-Key: mi-clave-abc123" https://api.ejemplo.com/datos
# En query parameter
curl -s "https://api.openweathermap.org/data/2.5/weather?q=Lima&appid=MI_API_KEY"
| Pro | Contra |
|---|---|
| Simple de implementar | No identifica al usuario (solo a la app) |
| Sin expiración (generalmente) | Si se filtra, acceso permanente |
2. Basic Auth
Envía usuario:contraseña codificado en Base64.
# curl lo maneja con -u
curl -s -u "usuario:contraseña" https://httpbin.org/basic-auth/usuario/contraseña | jq '.'
# Equivalente manual
TOKEN=$(echo -n "usuario:contraseña" | base64)
curl -s -H "Authorization: Basic $TOKEN" \
https://httpbin.org/basic-auth/usuario/contraseña | jq '.'
# IMPORTANTE: Base64 NO es cifrado, siempre usar HTTPS
3. Bearer Token (JWT, OAuth2)
El método más popular en APIs modernas.
# GitHub Personal Access Token
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
curl -s -H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/user | jq '{login, name}'
JWT (JSON Web Token)
Un JWT tiene 3 partes separadas por puntos:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. ← Header
eyJ1c2VyIjoiYW5hIiwicm9sIjoiYWRtaW4ifQ. ← Payload
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c ← Signature
# Decodificar un JWT
decode_jwt() {
echo "$1" | cut -d'.' -f2 | tr '_-' '/+' | \
awk '{while(length($0)%4)$0=$0"=";print}' | \
base64 -d 2>/dev/null | jq '.'
}
4. OAuth 2.0
Protocolo para autorización delegada. "Permitir a una app acceder a tus datos sin darle tu contraseña."
# Flujo Client Credentials (machine-to-machine)
TOKEN_RESPONSE=$(curl -s -X POST https://auth.ejemplo.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "scope=read:datos write:datos")
ACCESS_TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.access_token')
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://api.ejemplo.com/datos | jq '.'
5. mTLS (Mutual TLS)
Autenticación bidireccional con certificados. Usado en entornos de alta seguridad.
curl -s \
--cert /path/to/client.crt \
--key /path/to/client.key \
--cacert /path/to/ca.crt \
https://api.segura.com/datos
Rate Limiting
Las APIs limitan cuántas peticiones podés hacer.
# Verificar rate limit de GitHub
curl -sI https://api.github.com/users/octocat | grep -i "x-ratelimit"
# X-RateLimit-Limit: 60 → Máximo por hora
# X-RateLimit-Remaining: 57 → Quedan
# X-RateLimit-Reset: 1771632000 → Cuándo se resetea (epoch)
# Con token: 5000 req/hora
curl -sI -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/user | grep -i "x-ratelimit"
# Manejar rate limit en scripts
check_rate_limit() {
local headers
headers=$(curl -sI -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/rate_limit)
remaining=$(echo "$headers" | grep -i "x-ratelimit-remaining" | awk '{print $2}' | tr -d '\r')
reset=$(echo "$headers" | grep -i "x-ratelimit-reset" | awk '{print $2}' | tr -d '\r')
echo "Restantes: $remaining"
if [[ "$remaining" -lt 10 ]]; then
now=$(date +%s)
wait_secs=$((reset - now))
echo "⚠️ Rate limit bajo. Esperar ${wait_secs}s"
sleep "$wait_secs"
fi
}
Ejemplo: Autenticación con múltiples servicios
#!/bin/bash
# multi-auth.sh - Script que conecta con múltiples APIs
# GitHub (Bearer token)
github_api() {
curl -s \
-H "Authorization: token $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
"https://api.github.com$1"
}
# Docker Hub (Basic → Bearer)
dockerhub_api() {
local token
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/nginx:pull" | jq -r '.token')
curl -s -H "Authorization: Bearer $token" "$1"
}
# Uso
echo "=== GitHub ==="
github_api "/user" | jq '{login, repos: .public_repos}'
echo "=== Docker Hub ==="
dockerhub_api "https://registry-1.docker.io/v2/library/nginx/tags/list" | jq '.tags[:5]'
Ejemplo: Gestor de tokens
#!/bin/bash
TOKEN_FILE="/tmp/.api-token"
TOKEN_EXPIRY_FILE="/tmp/.api-token-expiry"
get_token() {
local now
now=$(date +%s)
# Verificar si el token cacheado sigue vigente
if [[ -f "$TOKEN_FILE" && -f "$TOKEN_EXPIRY_FILE" ]]; then
local expiry
expiry=$(cat "$TOKEN_EXPIRY_FILE")
if [[ "$now" -lt "$expiry" ]]; then
cat "$TOKEN_FILE"
return 0
fi
fi
# Obtener nuevo token
echo "Renovando token..." >&2
local token="simulated-token-$(date +%s)"
local expires_in=3600
echo "$token" > "$TOKEN_FILE"
echo "$((now + expires_in))" > "$TOKEN_EXPIRY_FILE"
chmod 600 "$TOKEN_FILE" "$TOKEN_EXPIRY_FILE"
echo "$token"
}
TOKEN=$(get_token)
curl -s -H "Authorization: Bearer $TOKEN" https://api.ejemplo.com/datos
Almacenar credenciales de forma segura
# ❌ MAL: Hardcoded en scripts
curl -H "Authorization: Bearer ghp_ABC123456" https://api.github.com/user
# ✅ BIEN: Variables de entorno (sesión actual)
read -s -p "GitHub Token: " GITHUB_TOKEN && export GITHUB_TOKEN
# ✅ BIEN: Archivo .env (no commitear)
echo "GITHUB_TOKEN=ghp_xxx" > .env
echo ".env" >> .gitignore
source .env
# ✅ BIEN: ~/.netrc
curl -n https://api.github.com/user
# ✅ BIEN: Gestor de secretos
# aws secretsmanager get-secret-value --secret-id mi-api-key
# vault kv get secret/api-keys
Resumen: Cuándo usar cada método
| Método | Cuándo usar | Seguridad |
|---|---|---|
| API Key | APIs públicas, rate limiting | ⭐ Baja |
| Basic Auth | Scripts simples, herramientas internas | ⭐⭐ Media |
| Bearer Token | APIs modernas, SPAs, mobile | ⭐⭐⭐ Alta |
| OAuth 2.0 | Login social, acceso delegado | ⭐⭐⭐⭐ Muy alta |
| mTLS | Infraestructura, microservicios | ⭐⭐⭐⭐⭐ Máxima |
Ejercicios
- Creá un Personal Access Token en GitHub y usalo para consultar tus repos con curl
- Decodificá un JWT de ejemplo y analizá su header y payload
- Verificá el rate limit de la GitHub API con y sin token — ¿cuál es la diferencia?
- Creá un script que obtenga un token, lo cachee, y lo reutilice en múltiples peticiones
- Implementá un script que conecte a 2 APIs con métodos de autenticación diferentes