Device flow : Auth avec Logto
Ce guide suppose que vous avez créé une Application de type "Native" avec le device flow comme flux d'autorisation dans la Console Logto.
Introduction
Le device authorization grant OAuth 2.0 (device flow) est conçu pour les appareils avec des capacités de saisie limitées, tels que les smart TV, consoles de jeux, outils CLI et appareils IoT. Il permet aux utilisateurs de démarrer le processus de connexion sur l'appareil mais de terminer l'authentification sur un autre appareil disposant d'un navigateur, comme un téléphone ou un ordinateur portable.
Puisque l'appareil lui-même ne peut pas gérer un flux de connexion basé sur un navigateur, l'appareil affiche un code court et une URL. L'utilisateur visite cette URL sur un autre appareil, saisit le code et se connecte. Pendant ce temps, l'appareil d'origine interroge Logto jusqu'à ce que l'autorisation soit terminée.
Obtenir les identifiants de l'application
Dans votre Console Logto, accédez à la page de détails de votre application pour obtenir les identifiants suivants :
- App ID : L'identifiant unique de votre application (également appelé
client_id). - Logto endpoint : L'endpoint de votre serveur d'autorisation Logto. Vous pouvez le trouver dans la Console Logto sous "Détails de l'application".
Pour Logto Cloud, l'endpoint est https://{your-tenant-id}.logto.app.
Les applications device flow sont des clients publics, donc aucun App Secret n'est requis.
Demander un device code
Démarrez le device flow en envoyant une requête POST à l'endpoint d'autorisation de l'appareil :
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 réponse inclut :
| Champ | Description |
|---|---|
device_code | Un code unique que votre application utilise lors de l'interrogation de l'endpoint de jeton. |
user_code | Un code court à afficher à l'utilisateur pour qu'il le saisisse dans le navigateur. |
verification_uri | L'URL où l'utilisateur saisit le user_code. |
verification_uri_complete | Une URL avec le user_code pré-rempli. Les utilisateurs peuvent visiter cette URL directement pour éviter la saisie manuelle du code — vous pouvez la présenter en QR code, lien cliquable, etc. |
expires_in | La durée de vie en secondes de device_code et user_code. Arrêtez l'interrogation après expiration. |
Afficher l'URL de vérification à l'utilisateur
Affichez le user_code et le verification_uri sur l'écran de votre appareil.
Vous pouvez également utiliser verification_uri_complete qui a le code pré-rempli — l'utilisateur n'a qu'à confirmer. La façon de le présenter vous appartient : QR code, lien cliquable, etc.
Interroger pour les jetons
Pendant que l'utilisateur termine l'authentification dans le navigateur, votre appareil doit interroger l'endpoint de jeton. Votre application doit attendre au moins 5 secondes entre chaque requête d'interrogation :
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'
Remplacez DEVICE_CODE par la valeur device_code de la réponse d'autorisation de l'appareil.
Arrêtez l'interrogation lorsque :
- Vous recevez une réponse de jeton réussie.
- Le temps
expires_inde la réponse device code est écoulé. - Vous recevez une erreur non réessayable telle que
expired_tokenouaccess_denied.
Réponse de jeton
Après l'approbation de l'utilisateur, la réponse inclut :
| Champ | Description |
|---|---|
access_token | Le jeton d’accès (Opaque token). Il s'agit d'une chaîne opaque par défaut ; lorsqu'une resource est demandée, c'est un JWT avec aud défini sur l'URI de la ressource. |
id_token | Le jeton d’identifiant (ID token) contenant les revendications d'identité de l'utilisateur. Présent uniquement si la portée openid est demandée. |
refresh_token | Utilisé pour obtenir de nouveaux jetons sans ré-authentification. Présent uniquement si la portée offline_access est demandée. |
token_type | Toujours Bearer. |
expires_in | Durée de vie du jeton en secondes. |
scope | Les portées accordées par le serveur d'autorisation. |
Point de contrôle : Testez votre device flow
Testez maintenant l'intégration de votre device flow :
- Lancez votre application et déclenchez le device flow pour obtenir un
device_codeet unuser_code. - Ouvrez le
verification_uridans un navigateur et saisissez leuser_code, ou utilisezverification_uri_completepour éviter la saisie manuelle du code. - Terminez le processus de connexion dans le navigateur.
- Vérifiez que votre application reçoit les jetons après l'interrogation.
Obtenir les informations utilisateur
Décoder les revendications du jeton d’identifiant (ID token)
Le id_token retourné dans la réponse de jeton est un JSON Web Token (JWT) standard. Vous pouvez décoder la charge utile encodée en Base64URL (la seconde partie du JWT, séparée par .) pour accéder aux revendications utilisateur de base sans requête réseau supplémentaire.
La charge utile décodée contient des revendications telles que sub (ID utilisateur), name, email, etc., selon les portées demandées.
En production, vous devez valider la signature du JWT avant de faire confiance à ses revendications. Utilisez le JWKS de votre endpoint Logto (https://your.logto.endpoint/oidc/jwks) pour vérifier le jeton.
Récupérer depuis l'endpoint userinfo
Le jeton d’identifiant (ID token) contient des revendications de base selon les portées demandées. Certaines revendications étendues (comme custom_data, identities) ne sont disponibles que via l'endpoint OIDC UserInfo :
curl --request GET 'https://your.logto.endpoint/oidc/me' \
--header 'Authorization: Bearer ACCESS_TOKEN'
Remplacez ACCESS_TOKEN par le jeton d’accès (Opaque token) obtenu dans la réponse de jeton (et non le JWT de ressource). La réponse est un objet JSON contenant les revendications de l'utilisateur selon les portées accordées.
Demander des revendications supplémentaires
Vous pouvez constater que certaines informations utilisateur sont absentes du jeton d’identifiant (ID token). Cela s'explique par le fait qu'OAuth 2.0 et OpenID Connect (OIDC) sont conçus pour suivre le principe du moindre privilège (PoLP), et Logto est construit sur ces standards.
Par défaut, des revendications limitées sont retournées. Si vous avez besoin de plus d'informations, vous pouvez demander des portées supplémentaires pour accéder à plus de revendications.
Une "revendication" est une affirmation faite à propos d'un sujet ; une "portée" est un groupe de revendications. Dans le cas actuel, une revendication est une information sur l'utilisateur.
Voici un exemple non normatif de la relation portée - revendication :
La revendication "sub" signifie "sujet", qui est l'identifiant unique de l'utilisateur (c'est-à-dire l'ID utilisateur).
Le SDK Logto demandera toujours trois portées : openid, profile, et offline_access.
Pour demander des portées supplémentaires, incluez-les dans le paramètre scope de la requête d'autorisation de l'appareil. Par exemple, pour demander l'email et le téléphone de l'utilisateur :
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'
Portées et revendications
Voici la liste des portées prises en charge et les revendications correspondantes :
Portées OIDC standard
openid (par défaut)
| Nom de la revendication | Type | Description |
|---|---|---|
| sub | string | L'identifiant unique de l'utilisateur |
profile (par défaut)
| Nom de la revendication | Type | Description |
|---|---|---|
| name | string | Le nom complet de l'utilisateur |
| username | string | Le nom d'utilisateur de l'utilisateur |
| picture | string | URL de la photo de profil de l'utilisateur final. Cette URL DOIT référencer un fichier image (par exemple, un fichier PNG, JPEG ou GIF), plutôt qu'une page Web contenant une image. Notez que cette URL DOIT référencer spécifiquement une photo de profil de l'utilisateur final adaptée à l'affichage lors de la description de l'utilisateur final, et non une photo quelconque prise par l'utilisateur final. |
| created_at | number | Date de création de l'utilisateur final. Le temps est représenté par le nombre de millisecondes écoulées depuis l'époque Unix (1970-01-01T00:00:00Z). |
| updated_at | number | Date de la dernière mise à jour des informations de l'utilisateur final. Le temps est représenté par le nombre de millisecondes écoulées depuis l'époque Unix (1970-01-01T00:00:00Z). |
D'autres revendications standard telles que family_name, given_name, middle_name, nickname, preferred_username, profile, website, gender, birthdate, zoneinfo et locale seront également incluses dans la portée profile sans avoir besoin de demander l'endpoint userinfo. Une différence par rapport aux revendications ci-dessus est que ces revendications ne seront retournées que si leurs valeurs ne sont pas vides, tandis que les revendications ci-dessus retourneront null si les valeurs sont vides.
Contrairement aux revendications standard, les revendications created_at et updated_at utilisent les millisecondes au lieu des secondes.
email
| Nom de la revendication | Type | Description |
|---|---|---|
string | L'adresse e-mail de l'utilisateur | |
| email_verified | boolean | Si l'adresse e-mail a été vérifiée |
phone
| Nom de la revendication | Type | Description |
|---|---|---|
| phone_number | string | Le numéro de téléphone de l'utilisateur |
| phone_number_verified | boolean | Si le numéro de téléphone a été vérifié |
address
Veuillez vous référer à la spécification OpenID Connect Core 1.0 pour les détails de la revendication d'adresse.
Les portées marquées (par défaut) sont toujours demandées par le SDK Logto. Les revendications sous les portées OIDC standard sont toujours incluses dans le jeton d’identifiant lorsque la portée correspondante est demandée — elles ne peuvent pas être désactivées.
Portées étendues
Les portées suivantes sont étendues par Logto et retourneront des revendications via l’endpoint userinfo. Ces revendications peuvent également être configurées pour être incluses directement dans le jeton d’identifiant via Console > JWT personnalisé. Voir Jeton d’identifiant personnalisé pour plus de détails.
custom_data
| Nom de la revendication | Type | Description | Inclus dans le jeton d’identifiant par défaut |
|---|---|---|---|
| custom_data | object | Les données personnalisées de l'utilisateur |
identities
| Nom de la revendication | Type | Description | Inclus dans le jeton d’identifiant par défaut |
|---|---|---|---|
| identities | object | Les identités liées de l'utilisateur | |
| sso_identities | array | Les identités SSO liées de l'utilisateur |
roles
| Nom de la revendication | Type | Description | Inclus dans le jeton d’identifiant par défaut |
|---|---|---|---|
| roles | string[] | Les rôles de l'utilisateur | ✅ |
urn:logto:scope:organizations
| Nom de la revendication | Type | Description | Inclus dans le jeton d’identifiant par défaut |
|---|---|---|---|
| organizations | string[] | Les identifiants d’organisation auxquels l'utilisateur appartient | ✅ |
| organization_data | object[] | Les données d’organisation auxquelles l'utilisateur appartient |
Ces revendications d’organisation peuvent également être récupérées via l’endpoint userinfo lors de l’utilisation d’un jeton opaque. Cependant, les jetons opaques ne peuvent pas être utilisés comme jetons d’organisation pour accéder à des ressources spécifiques à une organisation. Voir Jeton opaque et organisations pour plus de détails.
urn:logto:scope:organization_roles
| Nom de la revendication | Type | Description | Inclus dans le jeton d’identifiant par défaut |
|---|---|---|---|
| organization_roles | string[] | Les rôles d’organisation auxquels l'utilisateur appartient au format <organization_id>:<role_name> | ✅ |
Ressources API et organisations
Nous vous recommandons de lire d'abord 🔐 Contrôle d’accès basé sur les rôles (RBAC) pour comprendre les concepts de base de Logto RBAC et comment configurer correctement les ressources API.
Demander l'accès à des ressources API
Pour accéder à une ressource API spécifique, incluez le paramètre resource dans la requête d'autorisation de l'appareil :
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'
Une fois l'utilisateur autorisé et après avoir reçu un jeton de rafraîchissement (Refresh token), vous pouvez obtenir des jetons d’accès JWT pour la ressource 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 réponse contiendra un access_token JWT avec aud défini sur votre indicateur de ressource API.
Le refresh_token (Jeton de rafraîchissement) n'est disponible que si la portée offline_access est incluse dans la requête d'autorisation initiale. Stockez et utilisez toujours le dernier refresh_token, car Logto utilise la rotation des jetons.
Récupérer des jetons d’organisation
Si organisations est nouveau pour vous, veuillez lire 🏢 Organisations (Multi-tenancy) pour commencer.
Pour demander des informations liées à l'organisation, ajoutez la portée urn:logto:scope:organizations dans la requête d'autorisation de l'appareil :
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'
Une fois l'utilisateur connecté, vous pouvez récupérer des jetons d’organisation à l'aide du jeton de rafraîchissement :
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 réponse contiendra un jeton d’accès limité à l'organisation spécifiée.
Ressources API d'organisation
Pour obtenir un jeton d’accès pour une ressource API au sein d'une organisation, incluez à la fois les paramètres resource et 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'