はじめに
4/1にLINE WORKS APIの新しいバージョン「API2.0」が正式リリースされ、認証方式も新しくなったためPythonを実装例にまとめてみる。
まず、LINE WORKS API2.0には、認証方式が二種類ある。
- User Account認証
- LINE WORKSユーザーでログインを行い、Access Tokenを発行してAPIを利用する方法。
- スマホアプリやWebアプリ等に組み込む場合はこちらをつかう。
-
Service Account認証 ←今回はこちら
- 仮想管理者アカウントを使用して認証を行い、Access Tokenを発行してAPIを利用する方法。
- チャットボットやバッチ処理等でシステムがAPIを利用する場合はこちらを使う。
今回は、Service Account認証によるアクセストークンの取得までの流れと、それを使ったAPI呼び出しの一例としてBotのメッセージ送信APIの実装例、そしてトークン更新についてまでをまとめる。
- 前準備
- JWTの生成
- アクセストークン発行
- APIリクエストを送る (トークにBotからメッセージ送信)
- リフレッシュトークンでアクセストークンを再発行
ドキュメント
前提
- LINE WORKSテナントを作成済み、かつ、Developer Consoleの操作権限があること。
- フリープラン以上 (有料プランである必要なし)
- 環境
- Python 3.9
1. 前準備
API2.0を使うために、まずはDeveloper Consoleで「アプリ」作成を行う。
API2.0では、API利用のための認証情報・権限設定はこのアプリで設定でき、また、用途に分けて複数のアプリを作成できる。
API利用のための以下の情報をアプリから取得する。
項目 | 取得方法 |
---|---|
Client ID | アプリ作成時に自動生成 |
Client Secret | アプリ作成時に自動生成 |
Service Account | Service Account認証で利用される仮想管理者アカウント。「発行」から作成する。 |
Private Key | Service Account認証で利用される、秘密鍵。Service Accountの発行後に発行する。 |
次に、アクセストークンに与える権限を「OAuth Scopes」で指定する。今回は、Botのメッセージ送信を行うために bot
scopeにチェックしておく。
2. JWTの生成
前準備としてアプリの設定の完了後、アクセストークン取得を実装していく。
Service Account認証には、OAuth 2.0の拡張仕様 「JWT Bearer Token Grant Type Profile for OAuth 2.0」 RFC7523 が採用されており、JWTを生成しアクセストークン発行を行う。
アクセストークンの取得のための情報をJWTの形でまとめて、署名付きフォーマット (= JWS ) として作成する。
JWSの作成に必要な情報は以下の通り。
- Client ID
- Service Account
- Private Key
今回は PyJWT を使ってJWS生成を実装する。
import jwt
from datetime import datetime
def get_jwt(client_id, service_account_id, privatekey):
"""アクセストークンのためのJWT取得
"""
current_time = datetime.now().timestamp()
iss = client_id
sub = service_account_id
iat = current_time
exp = current_time + (60 * 60) # 1時間
jws = jwt.encode(
{
"iss": iss,
"sub": sub,
"iat": iat,
"exp": exp
}, privatekey, algorithm="RS256")
return jws
3. アクセストークン発行
上記で作成したJWSを使ってアクセストークンを発行する。
アクセストークン発行では、以下の情報が必要。
- Client ID
- Client Secret
- Scope
- 今回は
bot
を指定する。
- 今回は
- 作成したJWS
import urllib
import requests
BASE_AUTH_URL = "https://auth.worksmobile.com/oauth2/v2.0"
def get_access_token(client_id, client_secret, scope, jws):
"""アクセストークン取得"""
url = '{}/token'.format(BASE_AUTH_URL)
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
params = {
"assertion": jws,
"grant_type": urllib.parse.quote("urn:ietf:params:oauth:grant-type:jwt-bearer"),
"client_id": client_id,
"client_secret": client_secret,
"scope": scope,
}
form_data = params
r = requests.post(url=url, data=form_data, headers=headers)
body = json.loads(r.text)
return body
リクエストに成功すると、以下のようにアクセストークンを含むJsonが返る。
{
"access_token":"jp1AAABFNKyxc7xsVRQVKrTNFchiiMkQrfJMDM6whobYxfbO4fsF23mvuxRvSuMY57DG4uPI/NI4eNMSt8sroqpqFhe3HemLI3OvCar5FFfOQdqUBgqFA/MaHZVXHqsNJgoX7KaGwDTum+zhEyfwjGSrrJZfSoRpTHHrwny4F4UDEA1Lep3dVUUUKAIQHcq0TwCjiWkMnJAXMEFFfbdVzH3FCv+kpb2OH1NbYzL376fXLh3vMUlyRBXPTf3Lv0bK5NsvjR3BNMR3GSvVzjM59lR5ctBK8PvtTdmaHbVGXzJBHv+S3mp1UuD0szSuxCsWUrdCS7/PiWbQwM4++k+WM/bta5EB9v9s9YQGlyklE3fqhnYLGx/9jWanFgrvptCambOW8lv5A==",
"refresh_token":"jp1AAAAVq8kTeVPKkD11iLMP1mTqzYOd2T/r2x6QoBM2P3D8X6FfDi9wG5Hepsmh/LVpo3n3d/jcP/rnhtEw1VOpU4MJnxHVzu1x5VhKRmG/o63HERu2bnMtFHQVsjhljcf5fpm+Q==",
"scope": "bot",
"token_type": "Bearer",
"expires_in": 86400
}
これに含まれる access_token
を使ってAPIリクエストを送り、また、 refresh_token
を使ってアクセストークンの再発行を行う。
4. APIリクエストを送る (トークにBotからメッセージ送信)
発行したアクセストークンを用いてAPIリクエストを送ってみる。
今回は、Botからトークへメッセージを送信するリクエストを送る。
※ Botの作成の仕方は割愛。 参考
import requests
import json
BASE_API_URL = "https://www.worksapis.com/v1.0"
def send_message(content, bot_id, user_id, access_token):
"""メッセージ送信"""
url = "{}/bots/{}/users/{}/messages".format(BASE_API_URL, bot_id, user_id)
headers = {
'Content-Type' : 'application/json',
'Authorization' : "Bearer {}".format(access_token)
}
params = content
form_data = json.dumps(params)
r = requests.post(url=url, data=form_data, headers=headers)
r.raise_for_status()
5. リフレッシュトークンでアクセストークンを再発行
アクセストークンは「24時間」が有効期限となっており、継続してAPIを使うためには再発行が必要。
再発行をするには、アクセストークンの取得時に返るリフレッシュトークン refresh_token
を使い、再発行リクエストを送る。
なお、リフレッシュトークンの有効期限は「90日間」となっている。
必要な情報は以下の通り。
- Client ID
- Client Secret
- リフレッシュトークン
- アクセストークン取得時に返る
refresh_token
- アクセストークン取得時に返る
再発行されるアクセストークンには、初回取得時に設定したScopeがそのまま付与される。
import requests
BASE_AUTH_URL = "https://auth.worksmobile.com/oauth2/v2.0"
def refresh_access_token(client_id, client_secret, refresh_token):
"""アクセストークン更新"""
url = '{}/token'.format(BASE_AUTH_URL)
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
params = {
"refresh_token": refresh_token,
"grant_type": "refresh_token",
"client_id": client_id,
"client_secret": client_secret,
}
form_data = params
r = requests.post(url=url, data=form_data, headers=headers)
body = json.loads(r.text)
return body
まとめ
従来のAPIと比べると変わった点もいくつかあるが、scope周りも含めスッキリとまとまった印象。
ここまでのサンプルソースコードはこちら。
https://github.com/mmclsntr/lw-api-2_0-python-send-message-sample