跳到內容

Device Authorization Grant

Device Authorization Grant 由 RFC 8628 定義,是一種針對輸入受限裝置設計的授權流程。

許多連網裝置沒有瀏覽器或完整的輸入介面:

  • Smart TV、串流裝置——只有遙控器,無法輸入帳號密碼
  • 遊戲主機——有瀏覽器但輸入體驗極差
  • IoT 裝置、印表機——可能完全沒有螢幕或鍵盤

這些裝置無法執行標準的 Authorization Code Flow,因為該流程需要使用者在瀏覽器中登入並授權。即使裝置內建了簡易瀏覽器,在遙控器上輸入密碼的體驗也很糟糕。

Device Authorization Grant 的解法是:讓使用者在另一台有瀏覽器的裝置(如手機或筆電)上完成授權,裝置本身只負責顯示一組驗證碼並等待結果

sequenceDiagram
    participant Device as 裝置(Client)
    participant AS as Authorization Server
    participant User as 使用者(另一台裝置的瀏覽器)

    Device->>AS: 1. Device Authorization Request
    AS->>Device: 2. 回傳 device_code、user_code、verification_uri

    Device->>User: 3. 顯示 verification_uri 和 user_code

    User->>AS: 4. 開啟 verification_uri,輸入 user_code
    AS->>User: 5. 使用者登入並授權

    loop 輪詢
        Device->>AS: 6. Token Request(帶 device_code)
        AS-->>Device: authorization_pending
    end

    AS->>Device: 7. 核發 Access Token

裝置向 Authorization Server 的 Device Authorization Endpoint 發送請求:

POST /device_authorization HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
client_id=DEVICE_CLIENT_ID
&scope=read:profile
參數必要性說明
client_idREQUIRED(Public Client)裝置的 Client 識別碼
scopeOPTIONAL申請的授權範圍

Confidential Client 需依 RFC 6749 Section 3.2.1 進行 Client 認證,但裝置通常是 Public Client。

Authorization Server 回傳驗證碼和使用者操作指示:

{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://auth.example.com/device",
"verification_uri_complete": "https://auth.example.com/device?user_code=WDJB-MJHT",
"expires_in": 1800,
"interval": 5
}
欄位必要性說明
device_codeREQUIRED裝置驗證碼,用於後續輪詢 Token
user_codeREQUIRED使用者驗證碼,顯示在裝置螢幕上供使用者輸入
verification_uriREQUIRED使用者需要造訪的 URL
verification_uri_completeOPTIONAL已包含 user_code 的完整 URL,可產生 QR Code
expires_inREQUIREDdevice_codeuser_code 的有效期(秒)
intervalOPTIONAL裝置輪詢的最小間隔秒數,預設 5 秒

裝置在螢幕上顯示指示,例如:

請在手機或電腦上開啟:
https://auth.example.com/device
輸入驗證碼:WDJB-MJHT

如果 Authorization Server 提供了 verification_uri_complete,裝置也可以顯示 QR Code,讓使用者掃碼直接開啟已帶入驗證碼的頁面,省去手動輸入的步驟。

使用者在另一台裝置的瀏覽器上:

  1. 開啟 verification_uri
  2. 登入 Authorization Server
  3. 輸入 user_code(或透過 QR Code 自動帶入)
  4. 確認授權範圍並同意

使用者操作的同時,裝置以固定間隔向 Token Endpoint 輪詢:

POST /token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
&client_id=DEVICE_CLIENT_ID
參數必要性說明
grant_typeREQUIRED固定值 urn:ietf:params:oauth:grant-type:device_code
device_codeREQUIREDStep 2 收到的裝置驗證碼
client_idREQUIRED(Public Client)裝置的 Client 識別碼

授權成功——使用者完成授權後,Token Endpoint 回傳 Access Token:

{
"access_token": "eyJhbGciOiJSUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "8xLOxBtZp8",
"scope": "read:profile"
}

等待中——使用者尚未完成操作,裝置應繼續輪詢:

{
"error": "authorization_pending"
}

輪詢太頻繁——裝置必須將輪詢間隔增加 5 秒:

{
"error": "slow_down"
}

使用者拒絕——使用者明確拒絕授權,裝置應停止輪詢:

{
"error": "access_denied"
}

驗證碼過期——device_code 已超過 expires_in,整個流程需要重新開始:

{
"error": "expired_token"
}

user_code 需要使用者手動輸入,因此不能太長或太複雜。但太短的驗證碼容易被暴力破解。RFC 8628 建議使用 8 個字元的 base-20 編碼(約 34.5 bits 的熵),搭配速率限制來平衡兩者。

裝置透過輪詢得知授權結果,這代表在使用者完成操作前,裝置會持續對 Authorization Server 發送請求。interval 參數控制輪詢頻率,slow_down 錯誤讓 AS 能動態要求裝置降低頻率。即便如此,大量裝置同時輪詢仍可能對 AS 造成負擔。

verification_uri_complete 搭配 QR Code 可以大幅簡化使用者操作,但也讓釣魚攻擊更容易——攻擊者可以把自己的驗證碼做成 QR Code 誘騙使用者掃描。使用 QR Code 時,Authorization Server 應要求使用者確認裝置資訊。

user_code 的熵值遠低於 device_code(因為要手動輸入),攻擊者可能嘗試暴力猜測。Authorization Server 應實施速率限制,例如在每個 expires_in 週期內限制最多 5 次錯誤嘗試。

Device Authorization Grant 的特性是「授權的裝置」和「被授權的裝置」不同,這讓釣魚攻擊成為可能:攻擊者在自己的裝置上啟動流程,然後誘騙使用者在自己的手機上完成授權——使用者以為在授權自己的裝置,實際上卻授權了攻擊者的裝置。

Authorization Server 應在授權頁面上清楚標示正在授權的裝置資訊,幫助使用者辨識是否為自己的裝置。

大多數使用此流程的裝置都是 Public Client——client_secret 可以被反編譯取得。這代表 client_id 不能作為安全驗證的依據,授權的安全性完全依賴 device_code 的高熵值和 user_code 的速率限制。