Resumen

  • RFC 10017 ordena tres arquitecturas de mayor a menor seguridad: BFF completo, backend mediador de tokens y cliente OAuth en el navegador.
  • El BFF conserva tokens y credenciales confidenciales fuera de JavaScript, pero el código malicioso que ya se ejecuta en el origen aprobado aún puede enviar una orden mediante la cookie legítima del usuario.
  • El control efectivo exige gobernar origen y dependencias, cookies y CSRF, destinos y métodos del BFF, audiencia y alcance del token, autorización del recurso, confirmación de actos irreversibles y prueba del resultado final.

Una empleada abre el sistema de gastos y aprueba una factura. La interfaz no contiene tokens OAuth. El navegador solo conserva una cookie HttpOnly; el BFF guarda el refresh token y llama a las APIs. Esa separación es deliberada y correcta.

En la misma sesión, una biblioteca comprometida envía una segunda solicitud: cambia la cuenta de pago antes de confirmar la transferencia. El navegador adjunta la misma cookie. El BFF obtiene el access token y reenvía el comando. El sistema de pagos recibe credenciales válidas y procesa la modificación. Ningún secreto salió de su bóveda.

El incidente no demuestra que el BFF sea inútil. Demuestra que la custodia del token y la legitimidad del comando son afirmaciones distintas. RFC 10017, publicado en agosto de 2026 como Best Current Practice del IETF, convierte esa distinción en una decisión de arquitectura.

El atacante dentro del origen tiene más opciones que copiar

El punto de partida del RFC es código malicioso ejecutándose con los privilegios de la aplicación. Puede aparecer por XSS, por un recurso remoto comprometido o por otra falla de la cadena ejecutable. Desde el navegador, ese código puede leer los datos accesibles al frontend, interactuar con contextos del mismo origen, alterar funciones y emitir solicitudes que parecen provenir de la aplicación correcta.

El documento no reduce la amenaza a “robo de token”. Separa cuatro capacidades. La extracción única copia los valores presentes. La extracción persistente espera cada renovación. La adquisición de tokens nuevos inicia otro Authorization Code flow y aprovecha la sesión existente con el Authorization Server. El proxy a través del navegador usa directamente la sesión o el mecanismo que añade credenciales, sin extraer nada.

Cada defensa tiene un alcance preciso. Un access token corto limita una copia, no un script que roba el siguiente. La rotación del refresh token puede detectar reutilización, pero un atacante persistente puede tomar la última versión y evitar que el cliente legítimo la use. Un almacenamiento aislado protege el objeto existente, no impide pedir otro. PKCE evita que un tercero canjee un código interceptado, pero no identifica la intención del código que ya vive en el redirect origin registrado.

DPoP también conserva su valor exacto: un token copiado no sirve fuera del entorno que posee la clave. Sin embargo, un cliente público comprometido puede iniciar un flujo nuevo con una clave propia o usar la interfaz legítima en línea. RFC 10017 advierte de manera explícita que sender constraint no resuelve por sí solo la seguridad del cliente de navegador.

Qué cambia realmente con un BFF

En un BFF completo, el componente servidor pasa a ser el cliente OAuth confidencial. Ejecuta Authorization Code con PKCE, conserva access y refresh tokens, relaciona esos tokens con una sesión por cookie y canaliza todas las llamadas a los Resource Servers.

El diseño elimina tres riesgos concretos. JavaScript no tiene token que exfiltrar una vez ni de manera periódica. Tampoco puede canjear por sí solo un código nuevo como el cliente registrado, porque no dispone de las credenciales confidenciales del BFF. HttpOnly evita leer la cookie y convertir el control temporal del frontend en una sesión portable.

Lo que no elimina es la capacidad de dar órdenes durante la sesión activa. El código malicioso puede llamar al BFF; el navegador añade la cookie; el BFF traduce la sesión a un token. Por eso el componente debe mediar comandos, no actuar como un proxy genérico.

RFC 10017 exige controles estrictos de salida. Una ruta frontend debe corresponder a hosts y paths previamente aprobados. Los métodos permitidos deben ser explícitos. Ningún parámetro controlado por el navegador debería elegir libremente el destino que recibirá el token. Un BFF que acepta URL, path y método arbitrarios convierte la buena custodia en una poderosa primitive de reenvío.

La sesión por cookie exige otra disciplina. Secure y HttpOnly son obligatorios; SameSite=Strict, path /, ausencia de Domain y un prefijo adecuado son las recomendaciones. Nada de ello elimina CSRF. Si el navegador puede adjuntar la cookie, las rutas que cambian estado deben exigir evidencia anti-CSRF y de origen según su diseño.

El BFF concentra además credenciales, tokens, sesiones y routing. Puede observar toda la relación entre frontend y APIs, una posición útil para rate limits y detección de anomalías. También se vuelve un punto de capacidad, disponibilidad y recuperación que necesita dueño.

El mediador devuelve el riesgo que decide devolver

El backend mediador de tokens mantiene el refresh token y actúa como cliente confidencial, pero entrega access tokens al navegador. La aplicación llama directamente a los Resource Servers. Esta opción reduce el coste de proxy y evita que el refresh token llegue al frontend.

Su límite es estructural. El access token vuelve a estar disponible para código malicioso. Ocultarlo en memoria aislada no basta si la sesión puede pedir otro al mediador. El atacante no necesita conservar autoridad de largo plazo para causar un efecto inmediato.

También queda sin normalizar un reparto de DPoP en el que el backend obtiene el token y el navegador lo usa. No se debe convertir ese vacío en una garantía dibujada. RFC 10017 aconseja evaluar primero un BFF completo y adoptar mediación solo cuando las necesidades impidan el proxy integral. La excepción debe decir qué necesidad, qué alcance y qué duración de token acepta.

El cliente de navegador sigue siendo público

En la tercera arquitectura, el propio frontend ejecuta todas las responsabilidades OAuth. Un secreto incluido en el paquete es observable y no prueba la identidad de un cliente confidencial. Authorization Code con PKCE, redirect URIs exactos y protección CSRF son mínimos obligatorios. Si se emiten refresh tokens, deben rotarse o vincularse al emisor y tener un máximo o una caducidad por inactividad.

El origen —esquema, host y puerto— se convierte en una frontera práctica. El RFC recomienda una aplicación por origen. Alojar productos no relacionados bajo el mismo origen mezcla privilegios aunque sus equipos y repositorios sean distintos. CORS, CSP y los flujos postMessage son más auditables cuando esa frontera tiene un solo responsable.

CORS solo decide si el navegador puede exponer una respuesta cross-origin. No sustituye la autorización del servidor ni distingue el script legítimo del hostil dentro de un origen permitido. En mensajería entre ventanas, ambos extremos deben comprobar exactamente los origins.

El espejismo del Service Worker soberano

Un Service Worker puede guardar tokens en un contexto aislado y añadirlos a solicitudes sin entregarlos a la página. Parece un BFF local. RFC 10017 no recomienda usarlo como guardián del flujo OAuth porque el código hostil puede desregistrarlo y abrir un nuevo contexto que ya no pasa por su control. Allí puede iniciar otro flujo y extraer los tokens recién emitidos.

La conclusión es más amplia. Aislar una credencial no crea autoridad permanente sobre el origen. Una clave Web Crypto no exportable puede impedir que JavaScript lea sus bytes, pero no garantiza almacenamiento hardware ni evita necesariamente que código hostil pida utilizarla en el entorno vivo.

La evidencia debe llegar al commit

Un registro útil enlaza la versión del frontend y sus dependencias, el origen, un hash de sesión, el resultado CSRF, la ruta BFF, el host/path/método resultante, la audiencia y scopes, la política del Resource Server, el estado del objeto, la clave de idempotencia y el resultado de commit. No requiere guardar tokens, cookies o secretos sin procesar.

Las pruebas deben fallar por capas: intento de leer un token; robo después de rotación; flujo nuevo en iframe; solicitud al mediador; comando BFF sin exfiltración; manipulación del destino; repetición de una transferencia tras perderse la respuesta. “OAuth pasó” no explica cuál de esas autoridades funcionó.

Running-Code Primacy impide que la etiqueta BFF sea tratada como resultado. Solo importan las restricciones que los componentes despliegan y ejecutan. Minimum Initial Specification mantiene los intercambios OAuth comunes y verificables; la decisión sobre la consecuencia permanece local al servicio responsable. Una bóveda válida no convierte por sí sola un comando en mandato.