Flujo de dispositivo: Autenticación con Logto
Esta guía asume que has creado una Aplicación de tipo "Nativa" con flujo de dispositivo como el flujo de autorización en la Consola de Logto.
Introducción
El grant de autorización de dispositivo de OAuth 2.0 (flujo de dispositivo) está diseñado para dispositivos con capacidades de entrada limitadas, como smart TVs, consolas de juegos, herramientas CLI y dispositivos IoT. Permite a los usuarios iniciar el proceso de inicio de sesión en el dispositivo pero completar la autenticación en otro dispositivo con navegador, como un teléfono o portátil.
Dado que el propio dispositivo no puede manejar un flujo de inicio de sesión basado en navegador, el dispositivo muestra un código corto y una URL. El usuario visita esa URL en otro dispositivo, introduce el código e inicia sesión. Mientras tanto, el dispositivo original consulta Logto hasta que la autorización se completa.
Obtén las credenciales de la aplicación
En tu Consola de Logto, navega a la página de detalles de tu aplicación para obtener las siguientes credenciales:
- App ID: El identificador único de tu aplicación (también conocido como
client_id). - Endpoint de Logto: El endpoint de tu servidor de autorización Logto. Puedes encontrarlo en la Consola de Logto bajo "Detalles de la aplicación".
Para Logto Cloud, el endpoint es https://{your-tenant-id}.logto.app.
Las apps de flujo de dispositivo son clientes públicos, por lo que no se requiere App Secret.
Solicita un código de dispositivo
Inicia el flujo de dispositivo enviando una solicitud POST al endpoint de autorización de dispositivo:
curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access profile'
La respuesta incluye:
| Campo | Descripción |
|---|---|
device_code | Un código único para que tu app lo use al consultar el endpoint de token. |
user_code | Un código corto para mostrar al usuario y que lo introduzca en el navegador. |
verification_uri | La URL donde el usuario introduce el user_code. |
verification_uri_complete | Una URL con el user_code pre-rellenado. Los usuarios pueden visitar esta URL directamente para saltarse la introducción manual del código — puedes presentarla como código QR, enlace clicable, o cualquier otro método. |
expires_in | El tiempo de vida en segundos de device_code y user_code. Deja de consultar cuando esto expire. |
Muestra la URL de verificación al usuario
Muestra el user_code y el verification_uri en la pantalla de tu dispositivo.
Alternativamente, puedes usar verification_uri_complete que ya tiene el código pre-rellenado — el usuario solo necesita confirmar. Cómo lo presentes depende de ti: un código QR, un enlace clicable, etc.
Consulta por tokens
Mientras el usuario completa la autenticación en el navegador, tu dispositivo debe consultar el endpoint de token. Tu app debe esperar al menos 5 segundos entre solicitudes de consulta:
curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
--data-urlencode 'device_code=DEVICE_CODE'
Reemplaza DEVICE_CODE con el valor de device_code de la respuesta de autorización de dispositivo.
Deja de consultar cuando:
- Recibas una respuesta de token exitosa.
- El tiempo
expires_inde la respuesta del código de dispositivo haya expirado. - Recibas un error no reintentable como
expired_tokenoaccess_denied.
Respuesta de token
Después de que el usuario aprueba, la respuesta incluye:
| Campo | Descripción |
|---|---|
access_token | El token de acceso. Es una cadena opaca por defecto; cuando se solicita un resource, es un JWT con aud establecido al URI del recurso. |
id_token | El token de ID que contiene los reclamos de identidad del usuario. Solo presente cuando se solicita el alcance openid. |
refresh_token | Se utiliza para obtener nuevos tokens sin reautenticación. Solo presente cuando se solicita el alcance offline_access. |
token_type | Siempre Bearer. |
expires_in | Tiempo de vida del token en segundos. |
scope | Los alcances concedidos por el servidor de autorización. |
Punto de control: Prueba tu flujo de dispositivo
Ahora, prueba la integración de tu flujo de dispositivo:
- Ejecuta tu app y activa el flujo de dispositivo para obtener un
device_codey unuser_code. - Abre el
verification_urien un navegador e introduce eluser_code, o usaverification_uri_completepara saltar la introducción manual del código. - Completa el proceso de inicio de sesión en el navegador.
- Verifica que tu app reciba los tokens después de consultar.
Obtén información del usuario
Decodifica los reclamos del ID token
El id_token devuelto en la respuesta de token es un JSON Web Token (JWT) estándar. Puedes decodificar la carga útil codificada en Base64URL (la segunda parte del JWT, separada por .) para acceder a los reclamos básicos del usuario sin una solicitud de red adicional.
La carga útil decodificada contiene reclamos como sub (ID de usuario), name, email, etc., dependiendo de los alcances solicitados.
Para uso en producción, debes validar la firma del JWT antes de confiar en sus reclamos. Usa el JWKS de tu endpoint de Logto (https://your.logto.endpoint/oidc/jwks) para verificar el token.
Obtén información desde el endpoint userinfo
El ID token contiene reclamos básicos según los alcances solicitados. Algunos reclamos extendidos (como custom_data, identities) solo están disponibles a través del endpoint OIDC UserInfo:
curl --request GET 'https://your.logto.endpoint/oidc/me' \
--header 'Authorization: Bearer ACCESS_TOKEN'
Reemplaza ACCESS_TOKEN con el token de acceso opaco (no el token de recurso JWT) obtenido de la respuesta de token. La respuesta es un objeto JSON que contiene los reclamos del usuario según los alcances concedidos.
Solicita reclamos adicionales
Puede que notes que falta alguna información del usuario en el ID token. Esto se debe a que OAuth 2.0 y OpenID Connect (OIDC) están diseñados para seguir el principio de privilegio mínimo (PoLP), y Logto está construido sobre estos estándares.
De forma predeterminada, se devuelven reclamos limitados. Si necesitas más información, puedes solicitar alcances adicionales para acceder a más reclamos.
Un "reclamo (Claim)" es una afirmación hecha sobre un sujeto; un "alcance (Scope)" es un grupo de reclamos. En el caso actual, un reclamo es una pieza de información sobre el usuario.
Aquí tienes un ejemplo no normativo de la relación alcance - reclamo:
El reclamo "sub" significa "sujeto", que es el identificador único del usuario (es decir, el ID del usuario).
El SDK de Logto siempre solicitará tres alcances: openid, profile y offline_access.
Para solicitar alcances adicionales, inclúyelos en el parámetro scope de la solicitud de autorización de dispositivo. Por ejemplo, para solicitar el correo electrónico y el teléfono del usuario:
curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access profile email phone'
Alcances y reclamos
Aquí tienes la lista de alcances (Alcances) soportados y los reclamos (Reclamos) correspondientes:
Alcances OIDC estándar
openid (predeterminado)
| Claim name | Type | Description |
|---|---|---|
| sub | string | El identificador único del usuario |
profile (predeterminado)
| Claim name | Type | Description |
|---|---|---|
| name | string | El nombre completo del usuario |
| username | string | El nombre de usuario del usuario |
| picture | string | URL de la foto de perfil del usuario final. Esta URL DEBE referirse a un archivo de imagen (por ejemplo, un archivo de imagen PNG, JPEG o GIF), en lugar de a una página web que contenga una imagen. Ten en cuenta que esta URL DEBERÍA referenciar específicamente una foto de perfil del usuario final adecuada para mostrar al describir al usuario final, en lugar de una foto arbitraria tomada por el usuario final. |
| created_at | number | Momento en que se creó el usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z). |
| updated_at | number | Momento en que se actualizó por última vez la información del usuario final. El tiempo se representa como el número de milisegundos desde la época Unix (1970-01-01T00:00:00Z). |
Otros reclamos estándar incluyen family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo y locale, que también se incluirán en el alcance profile sin necesidad de solicitar el endpoint userinfo. Una diferencia en comparación con los reclamos anteriores es que estos reclamos solo se devolverán cuando sus valores no estén vacíos, mientras que los reclamos anteriores devolverán null si los valores están vacíos.
A diferencia de los reclamos estándar, los reclamos created_at y updated_at utilizan milisegundos en lugar de segundos.
email
| Claim name | Type | Description |
|---|---|---|
string | La dirección de correo electrónico del usuario | |
| email_verified | boolean | Si la dirección de correo electrónico ha sido verificada |
phone
| Claim name | Type | Description |
|---|---|---|
| phone_number | string | El número de teléfono del usuario |
| phone_number_verified | boolean | Si el número de teléfono ha sido verificado |
address
Por favor, consulta OpenID Connect Core 1.0 para los detalles del reclamo de dirección.
Los alcances marcados como (predeterminado) siempre son solicitados por el SDK de Logto. Los reclamos bajo los alcances OIDC estándar siempre se incluyen en el token de ID cuando se solicita el alcance correspondiente; no se pueden desactivar.
Alcances extendidos
Los siguientes alcances son extendidos por Logto y devolverán reclamos a través del endpoint userinfo. Estos reclamos también pueden configurarse para incluirse directamente en el token de ID a través de Consola > JWT personalizado. Consulta Token de ID personalizado para más detalles.
custom_data
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| custom_data | object | Los datos personalizados del usuario |
identities
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| identities | object | Las identidades vinculadas del usuario | |
| sso_identities | array | Las identidades SSO vinculadas del usuario |
roles
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| roles | string[] | Los roles del usuario | ✅ |
urn:logto:scope:organizations
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| organizations | string[] | Los IDs de las organizaciones a las que pertenece el usuario | ✅ |
| organization_data | object[] | Los datos de las organizaciones a las que pertenece el usuario |
Estos reclamos de organización también pueden recuperarse a través del endpoint userinfo cuando se utiliza un token opaco. Sin embargo, los tokens opacos no pueden usarse como tokens de organización para acceder a recursos específicos de la organización. Consulta Token opaco y organizaciones para más detalles.
urn:logto:scope:organization_roles
| Claim name | Type | Description | Included in ID token by default |
|---|---|---|---|
| organization_roles | string[] | Los roles de organización a los que pertenece el usuario con el formato <organization_id>:<role_name> | ✅ |
Recursos de API y organizaciones
Recomendamos leer primero 🔐 Control de acceso basado en roles (RBAC) para entender los conceptos básicos de Logto RBAC y cómo configurar correctamente los recursos de API.
Solicita acceso para recursos de API
Para acceder a un recurso de API específico, incluye el parámetro resource en la solicitud de autorización de dispositivo:
curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access' \
--data-urlencode 'resource=https://your-api-resource-indicator'
Una vez que el usuario complete la autorización y recibas un refresh token, puedes obtener tokens de acceso JWT para el recurso de API:
curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'resource=https://your-api-resource-indicator'
La respuesta contendrá un access_token JWT con aud establecido a tu indicador de recurso de API.
El refresh_token solo está disponible cuando el alcance offline_access se incluye en la solicitud inicial de autorización de dispositivo. Siempre almacena y usa el último refresh_token, ya que Logto utiliza rotación de tokens.
Obtén tokens de organización
Si organizaciones es nuevo para ti, por favor lee 🏢 Organizaciones (Multi-tenancy) para comenzar.
Para solicitar información relacionada con la organización, añade el alcance urn:logto:scope:organizations en la solicitud de autorización de dispositivo:
curl --request POST 'https://your.logto.endpoint/oidc/device/auth' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'scope=openid offline_access urn:logto:scope:organizations' \
--data-urlencode 'resource=urn:logto:resource:organizations'
Una vez que el usuario haya iniciado sesión, puedes obtener tokens de organización usando el refresh token:
curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'organization_id=your-organization-id'
La respuesta contendrá un token de acceso limitado a la organización especificada.
Recursos de API de la organización
Para obtener un token de acceso para un recurso de API dentro de una organización, incluye ambos parámetros resource y organization_id:
curl --request POST 'https://your.logto.endpoint/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=your-application-id' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'refresh_token=REFRESH_TOKEN' \
--data-urlencode 'organization_id=your-organization-id' \
--data-urlencode 'resource=https://your-api-resource-indicator'