Saltar al contenido principal

Clase 03 — Autenticación y Autorización en APIs

Autenticación vs Autorización

ConceptoPreguntaEjemplo
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"
ProContra
Simple de implementarNo 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étodoCuándo usarSeguridad
API KeyAPIs públicas, rate limiting⭐ Baja
Basic AuthScripts simples, herramientas internas⭐⭐ Media
Bearer TokenAPIs modernas, SPAs, mobile⭐⭐⭐ Alta
OAuth 2.0Login social, acceso delegado⭐⭐⭐⭐ Muy alta
mTLSInfraestructura, microservicios⭐⭐⭐⭐⭐ Máxima

Ejercicios

  1. Creá un Personal Access Token en GitHub y usalo para consultar tus repos con curl
  2. Decodificá un JWT de ejemplo y analizá su header y payload
  3. Verificá el rate limit de la GitHub API con y sin token — ¿cuál es la diferencia?
  4. Creá un script que obtenga un token, lo cachee, y lo reutilice en múltiples peticiones
  5. Implementá un script que conecte a 2 APIs con métodos de autenticación diferentes