
Flujos Esenciales de OAuth
- Authentication and Authorization
OAuth es un estándar en el mundo de la seguridad web que permite a una aplicación acceder a los recursos alojados en otra aplicación en nombre de un usuario dueño de estos recursos, sin necesidad de que este último comparta sus credenciales de acceso con la aplicación cliente con la estamos interactuándo.
OAuth Flows
Curiosamente, (y probablemente por simple mala fortuna), en los varios cursos que realicé, cuando se tocaba el tema de OAuth, siempre se hablaba de que era un standard, de sus beneficios, plataformas dedicadas a su implementación, JWT, pero nunca se hacía incapié en los flujos. Como este año estuve trabajando implementando OAuth en algunos de mis proyectos, me toco refrescar un poco el tema y decidí tomar notas (este post) sobre los flujos de OAuth que a mi parecer son el componente esencial de este standard.
Lo primero que hay que entender es que OAuth tiene varios flujos de operación que varían según el tipo de aplicación y sus necesidades. Estos flujos definen la secuencia de pasos que se siguen para obtener un token de acceso, que es la "llave" que permite a la aplicación acceder a los recursos protegidos. Aprendamos un poco sobre ellos:
Authorization Code Flow o Authorization Code Grant
Los “protagonistas” de este flujo son:
- Dueño del recurso: Es el usuario al cual pertenece el recurso o recursos a ser accedidos.
- Cliente: Es la aplicación que necesita acceder al recurso o los recursos.
- Servidor de autorización: Es el servidor que, en simples palabras, otorgará permiso al cliente luego de haberlo consultado con el cliente.
- Servidor de recursos: Es el servidor que aloja el recurso en cuestión.
Este es el flujo más común y seguro. Para este flujo es necesario que el cliente sea una aplicación backend (lo sé, los nombres no ayudan a evitar una confusión) es decir no puede ser una SPA o una aplicación móvil. Un buen ejemplo sería una aplicación construida en Blazor o con algún template engine en Node.js como Ejs o Handlebars. Esto se debe a que, al ser una app backend, podemos mantener oculto el token, lo que añade seguridad.
Los pasos de este flujo son los siguientes:
- La aplicación cliente envía una petición de autorización al servidor de autorización. En esta petición va un identificador conocido como client Id, este client id fue entregado previamente por el servidor de autorización al cliente cuando este se registró inicialmente con el servidor de autorización. Además del cliente Id en esta petición va una uri de redirección (ya la discutiremos) y también puede ir algo conocido como scope, que no es más que el alcance que tendrá la aplicación cliente sobre los recursos del usuario en cuestión.
- En este punto el servidor de autorización le pedirá al dueño del recurso, mediante un prompt por ejemplo, que autorice a la aplicación cliente para acceder a los recursos solicitados.
- Si el usuario accede, será redirigido a la uri de redirección que el cliente le envió al servidor de autorización en el paso uno. Encadenado a la uri de redirección también estará presente un código de autorización que el cliente utilizará en el siguiente paso. Atención, este código no es el token de acceso necesario para acceder a los recursos.
- La aplicación cliente realiza otra petición privada al servidor de autorización, específicamente al endpoint encargado de entregar el token de autorización. En esta petición van adicionalmente, el código de autorización recibido en el paso anterior, el cliente Id nuevamente y un elemento conocido como cliente secret que, al igual que el client Id, fue definido entre el cliente y el servidor de autorización en el registro inicial.
- Si todo está correcto, el servidor de autorización entregará al cliente el token de acceso y, opcionalmente, un token de refresco.
- Una vez el cliente tiene en posesión el token de acceso este puede usarlo para realizar peticiones al servidor donde están alojados los recursos solicitados.
- El servidor de los recursos entonces validará el token que viene con estas peticiones para dar acceso o no a los recursos del usuario.

Este flujo es una extensión del Authorization Code Flow diseñado para proteger contra ataques de interceptación del código de autorización en aplicaciones públicas, como aplicaciones móviles y SPAs (Single-Page Applications) que se ejecutan completamente en el navegador.
Como podemos asumir, los protagonistas son los mismos que en el caso anterior, pero sí hay una pequeña variación en los pasos y, además, existe un componente adicional. Este componente es un secreto que genera el cliente que se conoce como Code Verifier del cual deriva un hash conocido como Code Challenge. El método de derivación se especifica en la petición y normalmente es Sha256.
El code verifier y code challenge son necesarios por el riesgo de la interceptación del código de autorización por una aplicación maliciosa en aplicaciones públicas (como SPAs o aplicaciones móviles). En estos entornos, el código de autorización puede quedar expuesto (por ejemplo, a través de la URL de redirección). Una aplicación maliciosa podría interceptar este código e intentar usarlo para obtener un token de acceso, suplantando a la aplicación legítima. PKCE mitiga esto asegurando que solo la aplicación que inició la solicitud de autorización (y generó el code_verifier) pueda intercambiar el código por un token.
Los pasos son:
- La aplicación cliente genera el code verifier y con él genera el code challenge. Luego envía una petición de autorización al servidor de autorización que incluye client id, redirect uri, el code challenge y el code challenge method (por ejemplo Sha256) y puede tener scope, pero a diferencia del flujo previo no se enviará el client secret.
- El servidor de autorización, al igual que en el flujo anterior, autentica al dueño del recurso y le pide que autorice la aplicación cliente.
- Si el usuario autoriza, el servidor de autorización redirige al usuario de vuelta a la redirect_uri de la aplicación cliente, adjuntando un code (código de autorización) en la URL.
- La aplicación cliente realiza una petición privada al endpoint de token del servidor de autorización. Esta petición incluye el código recibido en el paso anterior, el client id, y esta vez el code verifier.
- El servidor de autorización verifica que el code_verifier proporcionado coincida con el code_challenge que se envió en la petición de autorización original y así asegurarse que es el mismo cliente que inició el proceso. Si coinciden y todo es correcto, el servidor de autorización responde con un access_token (y opcionalmente un refresh_token).
- La aplicación cliente utiliza el access_token para realizar peticiones autenticadas al servidor de recursos. El servidor de recursos valida el token para conceder o denegar el acceso a los recursos.
Client Credentials Flow
Este flujo se utiliza cuando la aplicación cliente necesita acceder a recursos en su propio nombre, sin la necesidad de la intervención de un usuario. Es común para escenarios como el acceso a APIs para tareas de administración o procesamiento por lotes.
Protagonistas:
- Cliente: La aplicación que necesita acceder a los recursos.
- Servidor de autorización: El servidor que emite el token de acceso basado en las credenciales del cliente.
- Servidor de recursos: El servidor que aloja los recursos que la aplicación cliente necesita acceder.
Pasos del flujo:
- La aplicación cliente realiza una petición al endpoint de token del servidor de autorización. Esta petición incluye:
- El client_id de la aplicación.
- El client_secret de la aplicación.
- Un parámetro grant_type con el valor client_credentials.
- Opcionalmente, el scope que define los permisos que la aplicación solicita para sí misma.
- El servidor de autorización autentica a la aplicación cliente utilizando su client_id y client_secret.
- Si la autenticación es exitosa y la aplicación está autorizada para el scope solicitado, el servidor de autorización emite un access_token.
- La aplicación cliente utiliza el access_token para realizar peticiones al servidor de recursos. El servidor de recursos valida el token para conceder o denegar el acceso a los recursos.
Este flujo es directo y eficiente para la autenticación de aplicaciones "máquina a máquina".
Otros flujos en OAuth
Device Code Flow
Este flujo está diseñado para dispositivos que tienen capacidades de entrada limitadas o no tienen un navegador web, como smart TVs, consolas de videojuegos o impresoras. Permite a los usuarios autorizar la aplicación en un dispositivo separado con un navegador web, como su teléfono o computadora.
Resource Owner Password Credentials
Es considerado altamente riesgoso ya que en este sucede una entrega directa de credenciales al cliente, es por eso que su uso se desaconseja en la mayoría de los escenarios modernos.