跳至主要內容

Device flow:使用 Logto 進行驗證 (Authentication)

備註:

本指南假設你已在 Logto Console 建立一個類型為「原生」且授權流程選擇 device flow 的應用程式。

簡介​

OAuth 2.0 device authorization grant(device flow)專為輸入能力有限的裝置設計,例如智慧電視、遊戲主機、CLI 工具與 IoT 裝置。它允許使用者在裝置上啟動登入流程,但在另一台有瀏覽器的裝置(如手機或筆電)上完成驗證 (Authentication)。

由於裝置本身無法處理瀏覽器登入流程,裝置會顯示一組短碼與一個網址。使用者在另一台裝置上造訪該網址、輸入短碼並登入。此時,原始裝置會持續輪詢 Logto,直到授權完成。

取得應用程式憑證​

在 Logto Console 中,前往你的應用程式詳細頁取得以下憑證:

  • App ID:你的應用程式唯一識別碼(亦稱 client_id)。
  • Logto endpoint:你的 Logto 授權伺服器端點,可於 Logto Console「應用程式詳細資訊」中找到。

若使用 Logto Cloud,端點為 https://{your-tenant-id}.logto.app。

備註:

Device flow 應用程式屬於公開用戶端,因此不需要 App Secret。

請求 device code​

啟動 device flow,向 device authorization 端點發送 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 的網址。
verification_uri_complete已預填 user_code 的網址。使用者可直接造訪此網址以略過手動輸入——你可將其呈現為 QR code、可點擊連結等任意方式。
expires_indevice_code 與 user_code 的存活秒數。到期後請停止輪詢。

將驗證網址顯示給使用者​

在裝置螢幕上顯示 user_code 與 verification_uri。

你也可以使用已預填短碼的 verification_uri_complete,使用者只需確認即可。呈現方式可自由選擇:QR code、可點擊連結等。

輪詢權杖​

當使用者在瀏覽器完成驗證 (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 authorization 回應中的 device_code。

停止輪詢的時機:

  • 收到成功的權杖回應。
  • device code 回應中的 expires_in 時間已過。
  • 收到不可重試的錯誤(如 expired_token 或 access_denied)。

權杖回應​

使用者授權後,回應內容包含:

欄位說明
access_token存取權杖 (Access token)。預設為不透明權杖 (Opaque token);若有指定 resource,則為帶有 aud 為資源 URI 的 JWT。
id_token含有使用者身分宣告 (Claims) 的 ID 權杖 (ID token)。僅在請求 openid 權限範圍 (Scope) 時提供。
refresh_token用於無需重新驗證 (Authentication) 取得新權杖的重新整理權杖 (Refresh token)。僅在請求 offline_access 權限範圍時提供。
token_type一律為 Bearer。
expires_in權杖存活秒數。
scope授權伺服器核發的權限範圍 (Scopes)。

檢查點:測試你的 device flow​

現在,測試你的 device flow 整合流程:

  1. 執行應用程式並觸發 device flow 以取得 device_code 與 user_code。
  2. 在瀏覽器開啟 verification_uri 並輸入 user_code,或直接使用 verification_uri_complete 省略手動輸入。
  3. 在瀏覽器完成登入流程。
  4. 確認應用程式輪詢後收到權杖。

取得使用者資訊​

解碼 ID 權杖宣告 (Claims)​

權杖回應中的 id_token 為標準 JSON Web Token (JWT)。你可以解碼 Base64URL 編碼的 payload(JWT 的第二段,以 . 分隔)來取得基本使用者宣告 (Claims),無需額外網路請求。

解碼後的 payload 會包含如 sub(使用者 ID)、name、email 等宣告,具體內容取決於請求的權限範圍 (Scopes)。

提示:

正式環境請務必驗證 JWT 簽章再信任其內容。可使用 Logto 端點的 JWKS(https://your.logto.endpoint/oidc/jwks)驗證權杖。

從 userinfo 端點取得​

ID 權杖會根據請求的權限範圍 (Scopes) 帶有基本宣告 (Claims)。部分擴充宣告(如 custom_data、identities)僅能透過 OIDC UserInfo 端點 取得:

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

將 ACCESS_TOKEN 替換為權杖回應中取得的不透明權杖 (Opaque access token)(非 JWT 資源權杖)。回應為根據授權範圍 (Scopes) 的 JSON 使用者宣告 (Claims)。

請求額外宣告 (Claims)​

你可能會發現 ID 權杖中缺少部分使用者資訊。這是因為 OAuth 2.0 與 OpenID Connect (OIDC) 遵循最小權限原則(PoLP),而 Logto 亦以此為基礎。

預設情況下,僅返回有限的宣告 (Claims)。如果你需要更多資訊,可以請求額外的權限範圍 (Scopes) 以存取更多宣告。

資訊:

「宣告 (Claim)」是對主體所做的斷言;「權限範圍 (Scope)」是一組宣告。在目前的情況下,宣告是關於使用者的一部分資訊。

以下是權限範圍與宣告關係的非規範性範例:

提示:

「sub」宣告表示「主體 (Subject)」,即使用者的唯一識別符(例如使用者 ID)。

Logto SDK 將始終請求三個權限範圍:openid、profile 和 offline_access。

若需額外權限範圍 (Scopes),請在 device authorization 請求的 scope 參數中加入。例如請求使用者 email 與手機:

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'

權限範圍 (Scopes) 與宣告 (Claims)​

以下是支援的權限範圍 (Scopes) 及對應的宣告 (Claims) 清單:

標準 OIDC 權限範圍 (Scopes)​

openid(預設)

Claim nameTypeDescription
substring使用者的唯一識別符 (The unique identifier of the user)

profile(預設)

Claim nameTypeDescription
namestring使用者全名 (The full name of the user)
usernamestring使用者名稱 (The username of the user)
picturestring終端使用者大頭貼的 URL。此 URL 必須指向圖片檔案(如 PNG、JPEG 或 GIF),而非包含圖片的網頁。請注意,此 URL 應明確指向適合描述終端使用者的個人照片,而非任意由終端使用者拍攝的照片。(URL of the End-User's profile picture. This URL MUST refer to an image file (for example, a PNG, JPEG, or GIF image file), rather than to a Web page containing an image. Note that this URL SHOULD specifically reference a profile photo of the End-User suitable for displaying when describing the End-User, rather than an arbitrary photo taken by the End-User.)
created_atnumber終端使用者建立時間。以自 Unix epoch(1970-01-01T00:00:00Z)以來的毫秒數表示。(Time the End-User was created. The time is represented as the number of milliseconds since the Unix epoch (1970-01-01T00:00:00Z).)
updated_atnumber終端使用者資訊最後更新時間。以自 Unix epoch(1970-01-01T00:00:00Z)以來的毫秒數表示。(Time the End-User's information was last updated. The time is represented as the number of milliseconds since the Unix epoch (1970-01-01T00:00:00Z).)

其他 標準宣告 (Standard claims) 包含 family_name、given_name、middle_name、nickname、preferred_username、profile、website、gender、birthdate、zoneinfo 及 locale 也會包含在 profile 權限範圍內,無需額外請求 userinfo endpoint。與上表宣告不同的是,這些宣告僅在其值不為空時才會回傳,而上表宣告若值為空則會回傳 null。

備註:

與標準宣告不同,created_at 與 updated_at 宣告使用毫秒而非秒為單位。

email

Claim nameTypeDescription
emailstring使用者的電子郵件地址 (The email address of the user)
email_verifiedboolean電子郵件地址是否已驗證 (Whether the email address has been verified)

phone

Claim nameTypeDescription
phone_numberstring使用者的電話號碼 (The phone number of the user)
phone_number_verifiedboolean電話號碼是否已驗證 (Whether the phone number has been verified)

address

請參閱 OpenID Connect Core 1.0 以瞭解 address 宣告的詳細資訊。

資訊:

標註為 (預設) 的權限範圍 (Scopes) 會由 Logto SDK 自動請求。當請求對應權限範圍時,標準 OIDC 權限範圍下的宣告 (Claims) 會始終包含於 ID 權杖 (ID token) 中,且無法關閉。

擴充權限範圍 (Extended scopes)​

以下權限範圍由 Logto 擴充,會透過 userinfo endpoint 回傳宣告 (Claims)。這些宣告也可透過 Console > Custom JWT 設定直接包含於 ID 權杖 (ID token) 中。詳情請參閱 自訂 ID 權杖 (Custom ID token)。

custom_data

Claim nameTypeDescriptionIncluded in ID token by default
custom_dataobject使用者的自訂資料 (The custom data of the user)

identities

Claim nameTypeDescriptionIncluded in ID token by default
identitiesobject使用者的連結身分 (The linked identities of the user)
sso_identitiesarray使用者的連結 SSO 身分 (The linked SSO identities of the user)

roles

Claim nameTypeDescriptionIncluded in ID token by default
rolesstring[]使用者的角色 (The roles of the user)✅

urn:logto:scope:organizations

Claim nameTypeDescriptionIncluded in ID token by default
organizationsstring[]使用者所屬的組織 ID (The organization IDs the user belongs to)✅
organization_dataobject[]使用者所屬的組織資料 (The organization data the user belongs to)
備註:

這些組織宣告 (Organization claims) 也可在使用 不透明權杖 (Opaque token) 時,透過 userinfo endpoint 取得。然而,不透明權杖無法作為組織權杖 (Organization tokens) 來存取組織專屬資源。詳見 不透明權杖與組織 (Opaque token and organizations)。

urn:logto:scope:organization_roles

Claim nameTypeDescriptionIncluded in ID token by default
organization_rolesstring[]使用者所屬組織角色,格式為 <organization_id>:<role_name> (The organization roles the user belongs to with the format of <organization_id>:<role_name>)✅

API 資源 (API resources) 與組織 (Organizations)​

我們建議先閱讀 🔐 角色型存取控制 (RBAC, Role-Based Access Control),以瞭解 Logto RBAC 的基本概念以及如何正確設定 API 資源。

請求 API 資源存取權​

若要存取特定 API 資源,請在 device authorization 請求中加入 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'

當使用者完成授權並取得重新整理權杖 (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 資源標示符 (Resource indicator) 的 JWT access_token。

備註:

只有在初始 device authorization 請求包含 offline_access 權限範圍 (Scope) 時才會取得 refresh_token。Logto 採用權杖輪替,請務必儲存並使用最新的 refresh_token。

取得組織權杖 (Organization tokens)​

若你對 組織 (Organizations) 不熟悉,請先閱讀 🏢 組織(多租戶,Multi-tenancy)。

若需請求組織相關資訊,請在 device authorization 請求中加入 urn:logto:scope:organizations 權限範圍 (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 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 資源 (Organization API resources)​

若要取得組織內 API 資源的存取權杖 (Access token),請同時帶入 resource 與 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'

延伸閱讀​

終端使用者流程:驗證流程、帳號流程與組織流程 (End-user flows: authentication flows, account flows, and organization flows) 設定連接器 (Configure connectors) 授權 (Authorization)