iT邦幫忙

2021 iThome 鐵人賽

DAY 20
0
Software Development

用Keycloak學習身份驗證與授權系列 第 20

Day19 - 【概念篇】OAuth flows: Device Code(1)

本系列文之後也會置於個人網站



      +----------+                                +----------------+
      |          |>---(A)-- Client Identifier --->|                |
      |          |                                |                |
      |          |<---(B)-- Device Code,      ---<|                |
      |          |          User Code,            |                |
      |  Device  |          & Verification URI    |                |
      |  Client  |                                |                |
      |          |  [polling]                     |                |
      |          |>---(E)-- Device Code       --->|                |
      |          |          & Client Identifier   |                |
      |          |                                |  Authorization |
      |          |<---(F)-- Access Token      ---<|     Server     |
      +----------+   (& Optional Refresh Token)   |                |
            v                                     |                |
            :                                     |                |
           (C) User Code & Verification URI       |                |
            :                                     |                |
            v                                     |                |
      +----------+                                |                |
      | End User |                                |                |
      |    at    |<---(D)-- End user reviews  --->|                |
      |  Browser |          authorization request |                |
      +----------+                                +----------------+

                    Figure 1: Device Authorization Flow

   The device authorization flow illustrated in Figure 1 includes the
   following steps:

   (A)  The client requests access from the authorization server and
        includes its client identifier in the request.

   (B)  The authorization server issues a device code and an end-user
        code and provides the end-user verification URI.

   (C)  The client instructs the end user to use a user agent on another
        device and visit the provided end-user verification URI.  The
        client provides the user with the end-user code to enter in
        order to review the authorization request.

Device Code Flow這個與前面幾個特別不一樣。在之前,以往都是從登入開始,然後跳轉頁面回到App(Client)。也就是通常先有的是前端通訊,然後才是後端通信。

這次不太同,開始不再是由資源擁有者發起,更像是由客戶端開始。甚至登入的方法與客戶端還沒有特別強烈的關聯。大致流程說明如下:

  1. 客戶端應用發起。向授權伺服器取得device_codeuser_code
  2. 客戶端應用將user_code交給資源擁有者。
  3. 資源擁有者透過某個端點(endpoint)與user_code進行授權。
  4. 客戶端應用透過device_code詢問授權伺服器是某有人授權。

在這裡device_code有點更像是傳統的sessionuser_code更像是之前的特殊密碼。

硬要比喻的話,就像是有一個充滿智慧的門,就先叫做「魔門」吧!這個魔門不但聰明還會識別人臉。它知道未來有一天,一定會有一個人來開啟它這扇門,但他不知道是誰。於是他把一段咒語--「魔門阿!魔門!誰是世界上最安全的鎖」--告訴管家。如果有一天有一個人將這個咒語告訴了管家,那就請管家將這個人的臉紀錄下來,並告訴魔門。當這個人走到魔門前面的時候,魔門就認得這張人臉,也就會自動開門了。

怕有人不知道。「魔鏡」的故事聽過吧XD

雖然這個比喻並不完全匹配,但是這裡的「魔鏡」有點像是客戶端;「管家」仍然是授權伺服器。與之前幾個流程相比,有點像是反過來走。

事前準備 - 建立一個新的Client example-device-app

由於OAuth Playground和OAuth.tools都不太能很好的用來理解這個模式。所以這一個會分成兩個部分介紹,除了實際走走上面提到的流程,還會在實際開發一個簡易的客戶端。如此,希望能夠使各位能夠更明白Device Code Flow。

那麼就先來再建立一個客戶端。

儘管用之前的「oauth_tools」或是調整「my-quick-start-app」也可以。不過還是從頭來一遍吧!

  • Client ID: example-device-app
  • Root URL: http://localhost:4200/

雖然這次Root URL並不是很重要,但還是填上與「my-quick-start-app」相同的值吧!

然後注意這次的Access Type需要選擇confidential並且將Oauth 2.0 Device Authorization Grant啓用。

然後先將 Credentials > Secret 記下來。

這麼一來前置工作就算是準備好了。

取得device_codeuser_code

這次要用HTTP POST的方法打http://localhost:8080/auth/realms/quick-start/device這個端點。

這次需要配合 Client Credentials 模式。所以不但要給client_id,也需要client_secretclient_secret填入剛剛所記下來的secret

  • client_id: example-device-app
  • client_secret: <方才記錄下來的secret>

在送出request後會得到一些資訊。

{
    "device_code": "boTQ6vd49RXTOYOb7dwXBCpHYskzOjXvDPjkXxniMN0",
    "user_code": "HZYO-ROXJ",
    "verification_uri": "http://localhost:8080/auth/realms/quick-start/device",
    "verification_uri_complete": "http://localhost:8080/auth/realms/quick-start/device?user_code=HZYO-ROXJ",
    "expires_in": 600,
    "interval": 5
}

其中最重要的是device_codeuser_codeverification_uri

到這邊算是初步完成了,但你可以先透過token_endpoint,也就是http://localhost:8080/auth/realms/quick-start/protocol/openid-connect/token這個端點確定一下。

除了需要給與device_code以外,還需要將grant_type改成urn:ietf:params:oauth:grant-type:device_code

  • grant_type: urn:ietf:params:oauth:grant-type:device_code
  • device_code: <方才取得的device_code>

現在,你應該會得到仍未有人登入授權。

魔門 真是孤獨阿~

{
    "error": "authorization_pending",
    "error_description": "The authorization request is still pending"
}

進行登入授權

接著,同樣透過剛剛知道的端點 verification_uri 登入。瀏覽器開啓 http://localhost:8080/auth/realms/quick-start/device ,並輸入同樣剛才得到的user_code:

或者是一個特殊的端點http://localhost:8080/auth/realms/quick-start/device?user_code=<user_code>。但總之登入後的是一個授權畫面。

在看下Yes允許授權後,提示的是登入成功,我們可以回到我們的應用。

取得存取權杖

同樣在嘗試取得一次存取權杖看看:

  • grant_type: urn:ietf:params:oauth:grant-type:device_code
  • device_code: <方才取得的device_code>

這次我們就可以取得存取權杖了~

{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ4VXh6WGR4UWpFNDNIZGdYbXJkUjBQZWxXN1ZoZWowbGRkR2NhN0VubXpZIn0.eyJleHAiOjE2MzI1Nzg5NTQsImlhdCI6MTYzMjU3ODY1NCwiYXV0aF90aW1lIjoxNjMyNTc3NTIxLCJqdGkiOiI5YTBhYTdkZi02NmEyLTRlMDgtYmZmNS05MjU2NDZlYmM1MTkiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvcXVpY2stc3RhcnQiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMzQ1YjFiY2EtOTgwNS00YjRiLWEwZjgtZGEyYzcwMTc2YzU5IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiZXhhbXBsZS1kZXZpY2UtYXBwIiwic2Vzc2lvbl9zdGF0ZSI6ImFmODhlZmZiLTVmNDgtNDgxZi04YWI2LTQ5MGRhMjY2YzY1ZCIsImFjciI6IjAiLCJhbGxvd2VkLW9yaWdpbnMiOlsiaHR0cDovL2xvY2FsaG9zdDo0MjAwIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJkZWZhdWx0LXJvbGVzLXF1aWNrLXN0YXJ0Iiwib2ZmbGluZV9hY2Nlc3MiLCJxdWljay1zdGFydC1leGFtcGxlLXJvbGUxIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQiLCJ3ZWJzaXRlIjoiaHR0cHM6Ly9ib2IuaWQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ2VuZGVyIjoibWFuIiwibmFtZSI6IkJvYiBMZWUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJib2IiLCJnaXZlbl9uYW1lIjoiQm9iIiwiZmFtaWx5X25hbWUiOiJMZWUiLCJlbWFpbCI6ImJvYkBmYWtlLmVtYWlsIn0.aPYPiG9icNnrxmmRUPoN_rf2eLhkprK7haXD9M6CpGRAHnjyzOkH1H2an3Au2I4LgFX7fdO95E5mF7NZ4gw-5SFe9Wof3Toe8araIQepurJXMd9Vx9Y6cO-htha796rkpUq2XNkcBLRHl9bN2zN3-2VM1X1pBqQPtDPeGckkp_2KH8u8n9UPxdq_lD-FZ_3-YzQav1RTs81QkxEBTn8Un7mzgRjdsmIkEJKYQqnhg86Xkw_bAGz-F-nDoj1XtHqjSIk_1EZ9brcgi05us-9ZL0tBViycQRCXEgJjq555omxh1XgjjuC_KPzA3y7hTTE75ZvO-3rc0sVy1DC-1AEtbg",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0NjUwNDBkYi1lNGJkLTRiYTYtOWM2Ny02ZWYxZGJmMmUxOWYifQ.eyJleHAiOjE2MzI1ODA0NTQsImlhdCI6MTYzMjU3ODY1NCwianRpIjoiZGI3NTBjOTMtODg3Mi00YmUxLTk3YWUtMmU2MTMxNzNjMDU2IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL3F1aWNrLXN0YXJ0IiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL3F1aWNrLXN0YXJ0Iiwic3ViIjoiMzQ1YjFiY2EtOTgwNS00YjRiLWEwZjgtZGEyYzcwMTc2YzU5IiwidHlwIjoiUmVmcmVzaCIsImF6cCI6ImV4YW1wbGUtZGV2aWNlLWFwcCIsInNlc3Npb25fc3RhdGUiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQiLCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiJhZjg4ZWZmYi01ZjQ4LTQ4MWYtOGFiNi00OTBkYTI2NmM2NWQifQ.1NGocwCZbpT-OjKnVj420Vql1_C3iwcZavuwJEk2sk0",
    "token_type": "Bearer",
    "not-before-policy": 1631743594,
    "session_state": "af88effb-5f48-481f-8ab6-490da266c65d",
    "scope": "email profile"
}

參考資料


上一篇
Day18 - 【概念篇】OAuth flows: PKCE
下一篇
Day20 - 【概念篇】OAuth flows: Device Code(2)
系列文
用Keycloak學習身份驗證與授權40

尚未有邦友留言

立即登入留言