メインコンテンツまでスキップ

Device flow: Logto での認証 (Authentication)

注記:

このガイドは、Logto コンソールで「ネイティブ」タイプかつ device flow を認可フローとして作成したアプリケーションがあることを前提としています。

はじめに

OAuth 2.0 デバイス認可グラント(device flow)は、スマート TV、ゲームコンソール、CLI ツール、IoT デバイスなど、入力機能が制限されたデバイス向けに設計されています。ユーザーはデバイス上でサインインプロセスを開始し、別のブラウザ搭載デバイス(スマートフォンやノート PC など)で認証 (Authentication) を完了できます。

デバイス自体がブラウザベースのサインインフローを処理できないため、デバイスは短いコードと URL を表示します。ユーザーは別のデバイスでその URL にアクセスし、コードを入力してサインインします。その間、元のデバイスは認可 (Authorization) 完了まで Logto にポーリングします。

アプリケーションのクレデンシャルを取得

Logto コンソールでアプリケーション詳細ページに移動し、次のクレデンシャルを取得します:

  • App ID:アプリケーションの一意の識別子(client_id とも呼ばれます)。
  • Logto エンドポイント:Logto 認可サーバーのエンドポイント。Logto コンソールの「アプリケーション詳細」で確認できます。

Logto Cloud の場合、エンドポイントは https://{your-tenant-id}.logto.app です。

注記:

Device flow アプリはパブリッククライアントのため、App Secret は不要です。

デバイスコードのリクエスト

device flow を開始するには、デバイス認可エンドポイントに POST リクエストを送信します:

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'

レスポンスには次が含まれます:

フィールド説明
device_codeトークンエンドポイントをポーリングする際にアプリで使用する一意のコード。
user_codeユーザーがブラウザで入力するために表示する短いコード。
verification_uriユーザーが user_code を入力するための URL。
verification_uri_completeuser_code があらかじめ入力された URL。ユーザーはこの URL に直接アクセスして手動入力を省略できます(QR コードやクリック可能なリンクなどで提示可能)。
expires_indevice_code および user_code の有効期間(秒)。この時間を過ぎたらポーリングを停止してください。

ユーザーに認証 (Authentication) URL を表示

デバイス画面に user_codeverification_uri を表示します。

または、コードがあらかじめ入力された verification_uri_complete を利用することもできます。ユーザーは確認するだけで済みます。QR コードやクリック可能なリンクなど、表示方法は自由です。

トークンのポーリング

ユーザーがブラウザで認証 (Authentication) を完了する間、デバイスはトークンエンドポイントをポーリングします。アプリはポーリングリクエストの間隔を 5 秒以上 空けてください:

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'

DEVICE_CODE はデバイス認可レスポンスの device_code に置き換えてください。

ポーリングを停止する条件

  • 正常なトークンレスポンスを受信した場合
  • device code レスポンスの expires_in 時間が経過した場合
  • expired_tokenaccess_denied など再試行不可のエラーを受信した場合

トークンレスポンス

ユーザーが承認すると、レスポンスには次が含まれます:

フィールド説明
access_tokenアクセス トークン (Access token)。デフォルトでは不透明トークン (Opaque token) ですが、resource を指定した場合は aud がリソース URI の JWT です。
id_tokenユーザーのアイデンティティクレームを含む ID トークン (ID token)。openid スコープをリクエストした場合のみ含まれます。
refresh_token再認証なしで新しいトークンを取得するためのリフレッシュ トークン (Refresh token)。offline_access スコープをリクエストした場合のみ含まれます。
token_type常に Bearer
expires_inトークンの有効期間(秒)。
scope認可サーバーによって付与されたスコープ。

チェックポイント:デバイスフローのテスト

デバイスフロー連携をテストしましょう:

  1. アプリを実行し、device flow をトリガーして device_codeuser_code を取得します。
  2. ブラウザで verification_uri を開き、user_code を入力するか、verification_uri_complete を使って手動入力を省略します。
  3. ブラウザでサインインプロセスを完了します。
  4. アプリがポーリング後にトークンを受信できることを確認します。

ユーザー情報の取得

ID トークン (ID token) クレームのデコード

トークンレスポンスで返される id_token は標準の JSON Web Token (JWT) です。Base64URL エンコードされたペイロード(JWT の 2 番目の部分、. で区切られた部分)をデコードすることで、追加のネットワークリクエストなしで基本的なユーザークレームにアクセスできます。

デコードされたペイロードには、リクエストしたスコープに応じて sub(ユーザー ID)、nameemail などのクレームが含まれます。

ヒント:

本番環境では、JWT のクレームを信頼する前に署名検証を行ってください。Logto エンドポイント(https://your.logto.endpoint/oidc/jwks)の JWKS を使ってトークンを検証できます。

userinfo エンドポイントから取得

ID トークンにはリクエストしたスコープに基づく基本的なクレームが含まれます。一部の拡張クレーム(custom_dataidentities など)は OIDC UserInfo エンドポイント からのみ取得できます:

curl --request GET 'https://your.logto.endpoint/oidc/me' \
--header 'Authorization: Bearer ACCESS_TOKEN'

ACCESS_TOKEN には、トークンレスポンスで取得した不透明トークン (Opaque token)(JWT リソーストークンではありません)を指定してください。レスポンスは、付与されたスコープに基づくユーザークレームを含む JSON オブジェクトです。

追加クレームのリクエスト

ID トークンに一部のユーザー情報が含まれていない場合があります。これは OAuth 2.0 および OpenID Connect (OIDC) が最小権限の原則(PoLP)に従って設計されており、Logto もこれらの標準に基づいているためです。

デフォルトでは、限られたクレーム (Claims) が返されます。より多くの情報が必要な場合は、追加のスコープ (Scopes) をリクエストして、より多くのクレーム (Claims) にアクセスできます。

備考:

「クレーム (Claim)」はサブジェクトについての主張であり、「スコープ (Scope)」はクレーム (Claims) のグループです。現在のケースでは、クレーム (Claim) はユーザーに関する情報の一部です。

スコープ (Scope) とクレーム (Claim) の関係の非規範的な例を示します:

ヒント:

「sub」クレーム (Claim) は「サブジェクト (Subject)」を意味し、ユーザーの一意の識別子(つまり、ユーザー ID)です。

Logto SDK は常に 3 つのスコープ (Scopes) をリクエストします:openidprofile、および offline_access

追加のスコープをリクエストするには、デバイス認可リクエストの scope パラメーターに含めてください。たとえば、ユーザーのメールアドレスや電話番号をリクエストする場合:

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'

スコープとクレーム

こちらはサポートされているスコープと対応するクレーム (Claims) の一覧です:

標準 OIDC スコープ

openid(デフォルト)

Claim nameType説明
substringユーザーの一意の識別子

profile(デフォルト)

Claim nameType説明
namestringユーザーのフルネーム
usernamestringユーザー名
picturestringエンドユーザーのプロフィール画像の URL。この URL は画像ファイル(例:PNG、JPEG、GIF 画像ファイル)を指す必要があり、画像を含む Web ページではありません。この URL は、エンドユーザーを説明する際に表示するのに適したプロフィール写真を特に参照するべきであり、エンドユーザーが撮影した任意の写真ではありません。
created_atnumberエンドユーザーが作成された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。
updated_atnumberエンドユーザー情報が最後に更新された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。

その他の 標準クレーム (Standard Claims) には、family_namegiven_namemiddle_namenicknamepreferred_usernameprofilewebsitegenderbirthdatezoneinfolocale などがあり、これらも profile スコープに含まれます(userinfo エンドポイントをリクエストする必要はありません)。上記のクレームとの違いは、これらのクレームは値が空でない場合のみ返される点です。一方、上記のクレームは値が空の場合 null が返されます。

注記:

標準クレーム (Standard Claims) とは異なり、created_at および updated_at クレームは秒ではなくミリ秒を使用しています。

email

Claim nameType説明
emailstringユーザーのメールアドレス
email_verifiedbooleanメールアドレスが認証済みかどうか

phone

Claim nameType説明
phone_numberstringユーザーの電話番号
phone_number_verifiedboolean電話番号が認証済みかどうか

address

アドレスクレームの詳細については OpenID Connect Core 1.0 を参照してください。

備考:

(デフォルト) と記載されたスコープは常に Logto SDK によってリクエストされます。標準 OIDC スコープ下のクレーム (Claims) は、対応するスコープがリクエストされた場合、常に ID トークン (ID token) に含まれます — 無効化できません。

拡張スコープ

以下のスコープは Logto によって拡張されており、userinfo エンドポイント を通じてクレーム (Claims) を返します。これらのクレームは Console > Custom JWT を通じて ID トークン (ID token) に直接含めるよう設定することもできます。詳細は カスタム ID トークン を参照してください。

custom_data

Claim nameType説明デフォルトで ID トークンに含まれるか
custom_dataobjectユーザーのカスタムデータ

identities

Claim nameType説明デフォルトで ID トークンに含まれるか
identitiesobjectユーザーのリンク済みアイデンティティ
sso_identitiesarrayユーザーのリンク済み SSO アイデンティティ

roles

Claim nameType説明デフォルトで ID トークンに含まれるか
rolesstring[]ユーザーのロール

urn:logto:scope:organizations

Claim nameType説明デフォルトで ID トークンに含まれるか
organizationsstring[]ユーザーが所属する組織 ID
organization_dataobject[]ユーザーが所属する組織データ
注記:

これらの組織クレーム (Organization Claims) は、不透明トークン (Opaque token) を使用している場合でも userinfo エンドポイント経由で取得できます。ただし、不透明トークン (Opaque token) は組織トークン (Organization token) として組織固有リソースへのアクセスには使用できません。詳細は 不透明トークン (Opaque token) と組織 (Organizations) を参照してください。

urn:logto:scope:organization_roles

Claim nameType説明デフォルトで ID トークンに含まれるか
organization_rolesstring[]ユーザーが所属する組織ロール(<organization_id>:<role_name> 形式)

API リソースと組織 (Organizations)

まず 🔐 ロールベースのアクセス制御 (RBAC) を読むことをお勧めします。これにより、Logto の RBAC の基本概念と API リソースを適切に設定する方法を理解できます。

API リソースへのアクセスリクエスト

特定の API リソースにアクセスするには、デバイス認可リクエストに resource パラメーターを含めます:

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'

ユーザーが認可 (Authorization) を完了し、リフレッシュ トークン (Refresh token) を受信したら、API リソース用の JWT アクセス トークン (Access 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 'resource=https://your-api-resource-indicator'

レスポンスには、aud が API リソースインジケーターに設定された JWT の access_token が含まれます。

注記:

refresh_token は、初回のデバイス認可リクエストで offline_access スコープを含めた場合のみ利用可能です。Logto はトークンローテーションを行うため、常に最新の refresh_token を保存・利用してください。

組織トークン (Organization tokens) の取得

組織 (Organizations) が初めての場合は、🏢 組織 (マルチテナンシー) をご覧ください。

組織関連の情報をリクエストするには、デバイス認可リクエストに urn:logto:scope:organizations スコープを追加します:

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'

ユーザーがサインインしたら、リフレッシュ トークン (Refresh token) を使って組織トークン (Organization 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'

レスポンスには、指定した組織にスコープされたアクセス トークン (Access token) が含まれます。

組織 API リソース

組織内の API リソース用のアクセス トークン (Access token) を取得するには、resourceorganization_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'

さらに読む

エンドユーザーフロー:認証 (Authentication) フロー、アカウントフロー、組織フロー コネクターの設定 認可 (Authorization)