Saltar al contenido principal

Flujo de dispositivo: Autenticación con Logto

nota:

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.

nota:

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:

CampoDescripción
device_codeUn código único para que tu app lo use al consultar el endpoint de token.
user_codeUn código corto para mostrar al usuario y que lo introduzca en el navegador.
verification_uriLa URL donde el usuario introduce el user_code.
verification_uri_completeUna 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_inEl 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_in de la respuesta del código de dispositivo haya expirado.
  • Recibas un error no reintentable como expired_token o access_denied.

Respuesta de token

Después de que el usuario aprueba, la respuesta incluye:

CampoDescripción
access_tokenEl 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_tokenEl token de ID que contiene los reclamos de identidad del usuario. Solo presente cuando se solicita el alcance openid.
refresh_tokenSe utiliza para obtener nuevos tokens sin reautenticación. Solo presente cuando se solicita el alcance offline_access.
token_typeSiempre Bearer.
expires_inTiempo de vida del token en segundos.
scopeLos 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:

  1. Ejecuta tu app y activa el flujo de dispositivo para obtener un device_code y un user_code.
  2. Abre el verification_uri en un navegador e introduce el user_code, o usa verification_uri_complete para saltar la introducción manual del código.
  3. Completa el proceso de inicio de sesión en el navegador.
  4. 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.

tip:

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.

info:

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:

tip:

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 nameTypeDescription
substringEl identificador único del usuario

profile (predeterminado)

Claim nameTypeDescription
namestringEl nombre completo del usuario
usernamestringEl nombre de usuario del usuario
picturestringURL 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_atnumberMomento 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_atnumberMomento 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.

nota:

A diferencia de los reclamos estándar, los reclamos created_at y updated_at utilizan milisegundos en lugar de segundos.

email

Claim nameTypeDescription
emailstringLa dirección de correo electrónico del usuario
email_verifiedbooleanSi la dirección de correo electrónico ha sido verificada

phone

Claim nameTypeDescription
phone_numberstringEl número de teléfono del usuario
phone_number_verifiedbooleanSi 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.

info:

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 nameTypeDescriptionIncluded in ID token by default
custom_dataobjectLos datos personalizados del usuario

identities

Claim nameTypeDescriptionIncluded in ID token by default
identitiesobjectLas identidades vinculadas del usuario
sso_identitiesarrayLas identidades SSO vinculadas del usuario

roles

Claim nameTypeDescriptionIncluded in ID token by default
rolesstring[]Los roles del usuario

urn:logto:scope:organizations

Claim nameTypeDescriptionIncluded in ID token by default
organizationsstring[]Los IDs de las organizaciones a las que pertenece el usuario
organization_dataobject[]Los datos de las organizaciones a las que pertenece el usuario
nota:

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 nameTypeDescriptionIncluded in ID token by default
organization_rolesstring[]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.

nota:

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'

Lecturas adicionales

Flujos de usuario final: flujos de autenticación, flujos de cuenta y flujos de organización Configurar conectores Autorización (Authorization)