Ejemplo de Device Code Flow de OAuth 2.0

¿Y si no tuviéramos un navegador en el dispositivo al que queremos dar permisos? Piensa en una televisión, una impresora, un asistente personal, un dispositivo IoT, etcétera. Por todo ello apareció un nuevo flujo en OAuth 2.0 llamado Device Code Flow. En este caso, el dispositivo en cuestión necesita que el usuario utilice otro dispositivo que tenga un navegador para iniciar sesión y otorgar el acceso a este primero.
Configuración del servidor de autorización
Como en los flujos anteriores, necesitamos registrar nuestra aplicación cliente en el servidor de autorización, en este caso Azure Active Directory.
Entra en el portal de Microsoft Azure, accede a Azure Active Directory y haz clic en la sección App registrations (Preview).

Ahora haz clic en el botón New registration del menú, para registrar nuestra futura aplicación cliente. Los valores que debes introducir son los siguientes:

Copia el Application (client) ID y el Directory (tenant) ID, que serán necesarios para llamar al servidor de autorización. Estos puedes encontrarlos en el apartado Overview de la aplicación que acabas de registrar.

Por último, en Authentication, debes habilitar a Yes el botón que se encuentra en el apartado Default Client Type, para que se trate al cliente como uno de tipo público (si no sabes lo que es esto, lee aquí), ya que no queremos guardar ningún secreto en nuestra aplicación.

Ya tienes todo lo que necesitas para poder ejecutar este flujo.
El cliente
Para este ejemplo, por simplicidad, no vamos a utilizar un dispositivo sin navegador. Vamos a simularlo con una aplicación web. Así que, como en los casos anteriores, he creado una aplicación web usando Node.js y Express:



Como ves, el código está dividido en pasos. Veamos uno a uno qué es lo que hacen:
Paso 1: Recuperar el código del dispositivo
Como primer paso, necesitamos que el servidor de autorización nos de un código asociado al dispositivo, en este caso nuestra web. En la página de inicio tenemos un botón que solicita el mismo.

Este hará una llamada a /get/the/code, que hará una llamada POST al endpoint /devicecode con el client id de la aplicación registrada y el scope que la aplicación necesita. El resultado será parecido al siguiente:

Como ves, el servidor de autorización ha devuelto un conjunto de valores:
- user_code: es el código que el usuario debe utilizar para autorizar que el dispositivo actúe en su nombre.
- device_code: lo utilizará nuestra aplicación como método de comprobación contra el endpoint /token, para saber si el usuario ha validado el código o qué ha hecho con él.
- verification_uri: es la URL donde el usuario debe dirigirse para validar el código.
- expires_in: es el tiempo en segundos en el que expirará el código.
- interval: se trata del número de segundos que el cliente debería esperar entre comprobaciones.
- message: se trata de un mensaje pensado para mostrarlo al usuario final. Simplemente recoge los valores verification_uri y user_code y los concatena en una frase.
En esta página, la aplicación está esperando a que el usuario acceda desde otro dispositivo a la dirección https://microsoft.com/devicelogin e introduzca el código de usuario, en este caso CBBE8LDVC.
¿Cómo sabe la aplicación si el usuario ha validado o no el código? Sencillo: este llamará al endpoint /token con el device_code cada 5 segundos, que es el valor de interval. Cuando el usuario valide el código satisfactoriamente se recibirá un 200. Mientras tanto, recibirá un 400 (Bad request). Para poder simularlo en este ejemplo, he creado un javascript en el cliente, que llama a /checking cada 5 segundos.

De hecho, si abres las herramientas del desarrollador del navegador, verás que se hace una petición cada 5 segundos.

Cuando el usuario introduce el código, inicia sesión y acepta el consentimiento, nuestra aplicación web nos redirigirá a /access/token para mostrarnos el token (esto no sólo con fines educativos).

Si pulsas sobre el botón Call Microsoft Graph API, podrás hacer la llamada al recurso protegido con el token obtenido a través del flujo Device Code.

Para que este ejemplo funcione, debes crear un archivo .env con los siguientes valores:

El código lo tienes en mi GitHub.
¡Saludos!