OAuth 2.0: guía práctica y segura para implementar autorización con tokens

Autor: Jeffry Chaves, Ing. en Sistemas – Diccionario Informático

1) Qué es OAuth 2.0 (y en qué se diferencia de OpenID Connect)

OAuth 2.0 es un marco de delegación de acceso: permite que una aplicación (cliente) pida permiso para actuar en nombre de un usuario sobre un recurso (API), obteniendo tokens de acceso con un alcance definido (scopes). No es, por sí mismo, un protocolo de autenticación; para “saber quién eres” suele usarse OpenID Connect (OIDC), que se apoya en OAuth y añade ID Tokens con información de identidad (claims).

Puntos clave para alinear expectativas:

  • OAuth = autorización (¿puedo hacer X en la API?).

  • OIDC = autenticación (¿quién eres?).

  • API Keys ≠ OAuth: las API keys no representan al usuario ni tienen scopes revocables por consentimiento.

  • “Inicio de sesión con…” (Google, Apple, etc.) típicamente se implementa con OIDC encima de OAuth.

Cuándo te interesa OAuth 2.0

  • Necesitas permisos granulados (scopes) y revocables.

  • Operas con APIs que exponen recursos de usuario/empresa.

  • Requieres delegación entre aplicaciones (p. ej., una app de terceros que publica en nombre del usuario).

[Marcador para tu experiencia]: aquí encaja una mini-anécdota sobre cuándo elegiste OAuth frente a API Keys y por qué.

2) Cómo funciona: actores, tokens y scopes

Actores

  • Authorization Server (AS): autentica al usuario, obtiene consentimiento y emite tokens.

  • Resource Server (RS / API): valida el token y aplica autorización.

  • Client (app): solicita tokens y accede a la API.

Tipos de token

  • Access Token: breve duración; autoriza llamadas a la API. Suele ser Bearer o JWT.

  • Refresh Token: vida más larga; permite renovar el access token sin re-pedir consentimiento (bajo políticas).

  • ID Token (si usas OIDC): para identidad; no debe usarse para acceder a recursos.

Scopes
Definen qué permisos se otorgan (p. ej., calendar.read, drive.file). Usa el principio de mínimo privilegio: solo los necesarios.

Ciclo básico

  1. La app redirige al AS → usuario se autentica y consiente.

  2. La app obtiene un authorization code (o equivalente según flujo).

  3. La app canjea el code por access token (y opcional refresh token).

  4. La app llama a la API con el access token en Authorization: Bearer <token>.

Ejemplo de petición a la API

GET /v1/profile HTTP/1.1
Host: api.ejemplo.com
Authorization: Bearer eyJhbGciOi...

[Marcador para tu experiencia]: breve nota de cómo definiste scopes y qué aprendiste al limitarlos.

3) Elegir el flujo correcto (web, SPA, móvil, backend, dispositivos)

Seleccionar bien el flujo evita huecos de seguridad y simplifica la implementación. Usa esta tabla de decisión:

Tipo de appFlujo recomendadoPor quéNotas de seguridad
Web tradicional (backend con sesión)Authorization CodeBackend puede guardar secretos y validar tokensUsa PKCE siempre; evita Implicit
SPA (JS en navegador)Authorization Code + PKCESin secreto en el front; PKCE protege el codeEvita Implicit; usa almacenamiento en memoria
Backend a backend (sin usuario)Client CredentialsAutenticación de la app ante la APIRestringe scopes a machine-to-machine
Nativas (iOS/Android/desktop)Authorization Code + PKCEPKCE mitiga robo de code en móvilesUsa redirects con esquemas válidos
TV/IoTDevice CodeSin teclado/ navegador completoExpira rápido; muestra códigos de usuario

Cuándo considerar Service Accounts (JWT)
Para integraciones server-side con permisos de proyecto/tenant (no de usuario). Úsalas con cuidado y rotación de claves.

[Marcador para tu experiencia]: un caso real de SPA con PKCE o de máquina a máquina con Client Credentials.

4) Configuración paso a paso (con checklist)

Checklist universal

  • Registrar la app (nombre, URL, redirect_uri exacta).

  • Definir scopes mínimos (y opcionales “de ampliación”).

  • Activar PKCE y desactivar Implicit.

  • Configurar rotación de refresh tokens (si aplica) y revocación.

  • Elegir librería oficial/fiable para tu lenguaje.

  • Implementar manejo de errores (invalid_grant, invalid_scope, consent_required, CORS).

  • Log segura (sin tokens en texto plano), trazabilidad y dashboards.

Ejemplo: intercambio de authorization code (con PKCE)

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=SplxlOBeZQQYbYS6WxSbIA&
redirect_uri=https%3A%2F%2Fapp.ejemplo.com%2Fcallback&
client_id=YOUR_CLIENT_ID&
code_verifier=J8Qk…_verifier

Renovación con refresh token

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
refresh_token=def50200…&
client_id=YOUR_CLIENT_ID

Validación de tokens

  • Si es JWT, valida firma, audiencia, emisor y expiración.

  • Si es opaque, usa introspection endpoint.

[Marcador para tu experiencia]: qué librería empleaste (p. ej., Spring Security, Passport, Authlib) y algún truco de configuración.

5) Seguridad moderna: PKCE, evitar implícito, rotación de tokens, DPoP/PAR/mTLS

Buenas prácticas que hoy son prácticamente estándar:

  • PKCE en todos los clientes públicos (SPA/móvil/desktop): añade code_verifier y code_challenge (S256).

  • Evitar el flujo implícito: reemplazar por Authorization Code + PKCE.

  • Rotación y revocación de refresh tokens: short-lived access tokens; revoca ante señales de riesgo.

  • DPoP (Proof-of-Possession): vincula el token a una clave del cliente para mitigar robo de tokens Bearer.

  • PAR (Pushed Authorization Requests): reduce manipulación de parámetros en el front.

  • mTLS: canal y cliente autenticados por certificado (alto nivel de seguridad).

  • Scopes mínimos y consentimiento claro.

  • Mitigaciones: CSRF en el redirect, control de redirect_uri exacta (sin comodines), antifraude de open redirect, protección ante mix-up de AS y validación de nonce/state.

[Marcador para tu experiencia]: cuenta un incidente evitado gracias a PKCE o a la rotación de refresh tokens.

6) Errores comunes y cómo depurarlos (redirect_uri, scopes, expiración, CORS)

redirect_uri_mismatch

  • Causa: diferencia exacta de URL (https, barra final, subdominio).

  • Solución: copia/pega exacto; evita comodines; separa “prod” y “staging”.

invalid_scope

  • Causa: pedir scopes no permitidos o mal escritos.

  • Solución: revisa catálogo de scopes; pide solo los necesarios.

invalid_grant / expired_token

  • Causa: reuso de authorization code, reloj desincronizado o token expirado.

  • Solución: usa una sola vez el code; sincroniza NTP; maneja 401 renovando tokens.

CORS y cookies

  • Causa: llamadas desde front con credenciales o encabezados cruzados.

  • Solución: configura CORS en la API; en SPA evita almacenar tokens en localStorage; prefiere in-memory y fetch con cabeceras adecuadas.

Depuración práctica

  • Activa Playgrounds/consolas de prueba del proveedor.

  • Loggea state, nonce, kid del JWT y corrélalo con el AS.

  • Usa herramientas como jwt.io (solo para prueba local) y scripts curl reproducibles.

[Marcador para tu experiencia]: cómo resolviste un invalid_grant o un problema de CORS en producción.

7) Buenas prácticas en producción (logs, auditoría, librerías oficiales, pruebas)

  • Librerías oficiales: reducen superficie de error y siguen cambios del proveedor.

  • Observabilidad: métricas de éxito/fracaso por grant, latencia de /token, tasas de revocación, anomalías.

  • Hardening: rotate secretos/llaves, política de caducidad, bloqueo de cliente si hay abuso, detección de IPs anómalas.

  • Pruebas: flujos end-to-end en staging, simulación de expiración de tokens, casos de caída del AS, test de consent re-prompt.

  • Documentación interna: diagramas por flujo, tabla de scopes con dueños y riesgos, runbooks de incidentes.

  • Cumplimiento: registra consentimientos y cambios de scopes; aplica minimización de datos.

8) FAQs rápidas de OAuth 2.0

¿OAuth 2.0 es autenticación o autorización? Autorización. Para autenticación de usuario usa OpenID Connect (emite ID Token).
¿Cuál es el mejor flujo para una SPA? Authorization Code + PKCE.
¿Necesito refresh tokens en SPA? Solo si la UX lo requiere; minimiza su vida y rota.
¿Bearer vs JWT? Bearer es un tipo de token; un JWT es un formato. Un access token puede ser JWT o no.
¿Puedo usar OAuth sin consentimiento visual? En Client Credentials (máquina a máquina) no hay usuario; en flujos de usuario, el consentimiento es parte central.


Conclusión

OAuth 2.0 te da un mecanismo sólido para delegar acceso con control fino via scopes y tokens. Elige el flujo correcto, aplica PKCE, evita Implicit, limita scopes, rota refresh tokens y, cuando el riesgo lo amerite, añade DPoP/PAR/mTLS. Con una buena observabilidad y runbooks claros, escalar y mantener tu capa de autorización se vuelve predecible.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *