筆記:網站整合LINE登入機制

原本只是想弄LINE通知,不過看到要oauth就覺得煩,乾脆直接了解LINE登入機制。這篇會講登入的作法,和需要存取的LINE API,以CURL指令舉例說明。建議可以先了解LINE BOT機制再來整合。


基本概念

讓網站可以接受LINE Login的方式,就是透過自訂的帳號榜定機制,常見的榜定是

1. 登入網站現有的帳號,再榜定LINE

2. 網站沒有帳號直接創建新帳號,將兩者帳號做榜定

因為做第二種表示你的網站是開放註冊新帳號的,就目前的應用因為是不開放帳號註冊,所以如果找不到榜定的LINE帳號資料就要顯示擋板網頁。

LINE登入流程

你的網站 -> 使用者按下LINE登入按鈕 -> LINE登入頁面 -> callback的URL

LINE會給callback網頁授權碼,剩餘交給我們自己處理。

  • Q1. 登入失敗呢?
    在callback時就會讓你知道它失敗/錯誤了。
  • Q2. 使用者名稱呢?
    取得LINE登入授權碼之後跟LINE的oauth2伺服器取得更多資料。
  • Q3. E-mail呢?
    你需要在LINE開發者中心裡面,在LINE登入中啟用E-mail權限,並且上傳一張圖寫明白為何需要E-mail。

事前準備

  • 在LINE開發者網站中建立一個LINE Login的設定
  • 開設你個人網站,網站需要具備HTTPS的憑證
    • 登入頁面,最簡單就是放個LINE登入按鈕連結
    • 接受callback的網頁 get
    • 儲存帳號和LINE登入對應的資料庫
以我手邊的side-project來說,會用Heroku+MongoDB或Google AppScript+Sheet完成這件事情,這樣都不用申請自己的HTTPS憑證。

LINE登入按鈕

官方有提供標準登入按鈕的圖示可以直接使用,我自己測試的所以只在網頁中寫一個登入連結下:

<a href="https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=${CHANNEL_ID}&redirect_uri=${CALLBACK_URL}&state=${STATE}&scope=profile%20openid&nonce=${NONCE}">
LINE login
</a>

  1. client_id就是你的LINE登入的Channel ID。
  2. redirect_uri 就是你的callback的URL。
    這裡因為是html的URL記得要用percentage encoding 
    以Herorku的APP舉例,原本的URL若是https://my-line-bot.herokuapp.com/callback,編碼後要改成https%3A%2F%2Fmy-line-bot.herokuapp.com%2Fcallback`。
  3. state 是你自己決定的內容,因為會被傳送到callback URL中,可以做確認來源或資料確認。
  4. nonce 是你自己決定的隨機碼,會被放 id_token 中。

你的Callback網頁

網頁要接受query參數

  • 固定參數: state 是我們在Login API自己決定的隨機碼。
  • 動態參數:
    • 成功時:
      1. code 即LINE授權碼。
      2. friendship_status_changed 是當官方LINE@好友狀態有改變時會傳遞。
    • 失敗時:
      1. error 錯誤類型。
      2. error_description 錯誤描述。

用LINE授權碼取得使用者名稱

從LINE授權碼取得使用者名稱,有兩個步驟:

  1. 存取token API
  2. 抓取使用者資訊, 有兩個方法:
    1. 使用access_token存取user profile API,取用displayName欄位
    2. 針對id_token的第二部份進行BASE64解碼,取用name欄位

存取token API

取得LINE授權碼的在10分鐘內都可以用來存取token API。

curl -v -X POST 'https://api.line.me/oauth2/v2.1/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d "redirect_uri=${CALLBACK_URL}" \
  -d "code=${LINE_AUTH_CODE}" \
  -d "client_id=${CHANNEL_ID}" \
  -d "client_secret=${CHANNEL_SECRET}"

  • redirect_uri 就是放你登錄在LINE開發者中心的callback url,必須完全相同。因為curl會幫忙轉換所以不用放precentage encoding的結果。
  • code 就是給LINE callback的授權碼。
  • client_id 就是你的LINE登入的Channel ID。
  • client_secret 就是你的LINE登入的Channel secret。

伺服器會回傳

{
    access_token: 'eyJhbG...Fdk',
    token_type: 'Bearer',
    refresh_token: 'VNd...c1c',
    expires_in: 2592000,
    scope: 'profile openid',
    id_token: 'eyJ0eX...kKc'
}

  • access_token 是用來取得使者資訊,驗證及撤銷時使用。
  • refresh_token 是用來刷新access_token用的。
  • id_token 是一種JWT格式,由兩個點(.)分隔的三段資訊,各段分別以BASE64編碼。

解碼id_token

使用JWT.io可以視覺化的看出JWT格式的三段資訊: header, payload, signature。我們取出第二段payload以BASE64解碼如下:

{
    "iss": "https://access.line.me",
    "sub": "U1fc...945",
    "aud": "16...18",
    "exp": 1633414357,
    "iat": 1633410757,
    "nonce": "09876xyz",
    "amr": [
        "linesso"
    ],
    "name": "Yung-Hsiang",
    "picture": "https://profile.line-scdn.net/0hLh8h...SH4t"
}

包含使用者名稱,token發出時間,到期時間

取得使用者資訊

curl -v -X GET https://api.line.me/v2/profile \
-H "Authorization: Bearer ${ACCESS_TOKEN}"

Bearer跟access_token之間有空格

伺服器回傳

{
    "userId":"U1fc...45",
    "displayName":"Yung-Hsiang",
    "statusMessage":"(Moon hehe)(Moon hehe)(Moon hehe)",
    "pictureUrl":"https://profile.line-scdn.net/0hL...H4t"
}

驗證access_token

這裡主要是用來確認是否還可用這個access_token跟剩餘時間。

curl -v -X GET \
"https://api.line.me/oauth2/v2.1/verify?access_token=${ACCESS_TOKEN}"

伺服器驗證成功回傳 http code 200

{
    "client_id":"16...18",
    "expires_in":2585320,
    "scope":"profile openid"
}

伺服器驗證失敗回傳 http code 400

{
    "error":"invalid_request",
    "error_description":"The access token revoked"
}

刷新access_token

curl -v -X POST 'https://api.line.me/oauth2/v2.1/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=refresh_token' \
-d "refresh_token=${REFRESH_TOKEN}" \
-d "client_id=${CHANNEL_ID}" \
-d "client_secret=${CHANNEL_SECRET}"

  • refresh_token 是用授權碼從token API取得,或是之前刷新時給的refresh_token。
  • client_id 就是你的LINE登入的Channel ID。
  • client_secret 就是你的LINE登入的Channel secret。

伺服器驗證回傳,相較於用登入授權時少了id_token欄位

{
    "access_token":"eyJhbG...Gv4",
    "token_type":"Bearer",
    "refresh_token":"VNdD...c1c",
    "expires_in":2592000,
    "scope":"profile openid"
}

撤銷access_token

這個方法相當於登出LINE,讓access_token不能再使用。

curl -v -X POST 'https://api.line.me/oauth2/v2.1/revoke' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d "client_id=${CHANNEL_ID}" \
-d "client_secret=${CHANNEL_SECRET}" \
-d "access_token=${ACCESS_TOKEN}"

  • client_id 就是你的LINE登入的Channel ID
  • client_secret 就是你的LINE登入的Channel secret
  • access_token 是放使用者登入的access_token

沒有回傳內容

參考資料

留言