7839

雑草魂エンジニアブログ

【Python/JWT】LINE WORKS の BOT の AccessToken を取得する

今回、LINE WORKS に新しく BOT を導入することになった。BOTの用途は、通知用であり、インタラクティブである必要はない。

通常の LINE の BOT を作成したことはあったが、LINE WORKS での BOT 作成は初だったので、備忘録として残しておく。

システム概要

今回、LINE WORKS + Power Automate(Teams)であるカレンダーの予定を抽出して、BOT で通知させることを想定している。概略図は以下の通りである。

f:id:serip39:20201230035719p:plain

今回の記事では、LINE WORKS のセットアップ部分、特にAccess_Tokenの取得について紹介する。

LINE WORKS の BOT 作成手順

公式ドキュメントに事細かに丁寧に書かれているので、詳細な手順は公式ドキュメントを是非見てほしい。

そして、1 の Server Token の発行手順は以下のようになっている。

  1. JWT 生成
  2. JWT 電子署名(signature)
  3. LINE WORKS 認証サーバーへの Token リクエス

f:id:serip39:20201230040542p:plain

今回、(Power Automate に組み込む前に)Pythonaccess_token の取得及びメッセージ送信試験を行った。(access_tokenは、24 時間以内利用されない場合には自動的に失効する。今回のシステムの仕様では、毎日使用するため、access_tokenが失効する可能性は低い。access_tokenを取得して、そのまま Power Automate に組み込むことを想定している。)

なお、実装したサンプルコードは GitHub に公開している。 pipenv を使って、Python仮想環境(開発環境)を即座に構築するだけで、サンプルプログラムの動作確認ができるようにしているので、どうぞ。

github.com

pipenv に関しては、以前の【Python】Pipenvを用いたPython仮想環境(開発環境)を参考にして欲しい。

プログラムを実行する前に、グローバル変数、LINE WORKSのBOTに使用する以下の設定パラメータを追記する必要がある。

# グローバル変数
DOMAIN_ID = ""
API_ID = ""
SERVER_API_CONSUMER_KEY = ""
SERVER_LIST_ID = ""
SERVER_LIST_PRIVATEKEY = ""
BOT_NO = ""

それぞれの値は、Developer Console で確認することができる。(事前に、BOTなどもこの時点で作成しておく必要がある。)

SERVER_LIST_PRIVATEKEY には、Server List(ID登録タイプ)の認証キーを設定するが、Developer Consoleではprivate_[日付].key のファイルがダウンロードされ、以下のように数行になっている。

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0B
〜省略〜
+juq+vKHrY7+CQgr/7bjZqmR
-----END PRIVATE KEY-----

このままだとグローバル変数に登録することができないので、改行されている部分を全て改行コードに書き換えて、一行とする。

$  cat private_20201229171641.key | sed -e :loop -e 'N; $!b loop' -e 's/\n/\\n/g' | pbcopy

上記のコマンドを実行することで、クリップボードにコピーされた状態になるので、そのままグローバル変数の部分にペーストする。

SERVER_LIST_PRIVATEKEY = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0B (省略)+juq+vKHrY7+CQgr/7bjZqmR\n-----END PRIVATE KEY-----"

全ての設定が完了次第、python get_token.py を実行することで BOT から「Hello World」と通知されれば完璧である。

ログから、access_tokenを確認することもできる。

$ python get_token.py
{'action': 'create jwt', 'status': 'success', 'message': 'JWT:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJiYTY3M2ZhOTBiNjQ0YWU2OGI4MjliNzIxM2MxMjFkYiIsImlhdCI6MTYwOTI2OTg3MiwiZXhwIjoxNjA5MjcxNjcyfQ.TlA5A86qKH6cQ4vKmKtpulhBYxZbxIg6fSLLYLNePqFb59uXpnte0etG0jsv2AyDquDcFZlUg62baHQil8V0mngo_OUcX51llQK3-Cx5BBahYSuMVU_FwMcTrtwJfBp0zLHRxpy5hrifTnafuzrRXbhrPixELnxYVoRGHglDbn39kmbylU-1zg5Fr1w__obiwUOSC2J80WmuwO8ugjoLx67xKYCuInFpyMGAG7zdRJLeoyeAuRBy7wA99LSLMS9vzdrDvGnzZjlP5etF2pDo7ZUbQOUSqFNin9CHVPdlOmW2rifQxRMsO5ZnNAtAZoHXpZBjgFQwei8xjuoYW0sILA'}
{'action': 'get access token', 'status': 'success', 'message': 'access_token:AAABCVee9HJEVlsdbn/egcTZVN+Cw3+c2VydmVySWQ+O8Up4ja2mud53VSj911kHu70OZ5CJ5Bi6bRcwPJE87ExNCZ/BGo4b13uYu4vsFn9qHUD5zZpILYKFb1c8k2mUUrLnc7PMooaWqyOAagGNugfiOepzWzdaMGNEWD2Dg/85wFO7rKjoUrsNiZOUCIKWR25vvbpEoKF2WW1xAYl8yZPFTwbPn9VfgTGsPoPtOlsEBPjUjp6e1WBTedVTsYlV3B17zz59Yb7n2iNYzMubw1/DAbEznTQYPsvoeiSggVMt3t6IguUGuXJIocD+qpZ59rmxIXO9tZ2yFj3BudqTo5uz5AHD07J2nTl9LJJC3wr6jtCqjnm/tTxH6TVPG'}

JWT とは

jwt.io

JWT とは、JSON Web Tokenの略である。(ジョットと読むらしい。)以下の3つの要素から構成され、それぞれは「.」で結合されている。また、それぞれは Base64エンコードされている必要がある。

  • ヘッダー:暗号化アルゴリズムトークンタイプなどのメタ情報
  • クレーム情報:任意の情報を付与できる(ユーザー認証情報など)
  • 署名:ヘッダーで指定した暗号化アルゴリズムで、秘密鍵を用いて生成される
[ヘッダー].[クレーム情報].[署名]

JWTの作り方

1. アルゴリズムとTokenタイプをヘッダに設定して、Base64エンコードする

$ echo -n '{"alg": "RS256", "typ": "JWT"}' | base64
eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9

2. クレーム情報を作成して、Base64エンコードする

$ echo -n '{"iss":"ba673fa90b644ae68b829b7213c121db","iat": 1609274027, "exp": 1609275827}' | base64
eyJpc3MiOiJiYTY3M2ZhOTBiNjQ0YWU2OGI4MjliNzIxM2MxMjFkYiIsImlhdCI6IDE2MDkyNzQwMjcsICJleHAiOiAxNjA5Mjc1ODI3fQ==
パラメータ 説明
iat JWT 生成日時(UNIX、単位:sec)
exp JWT 満了日時(UNIX、単位:sec)
iss LINE WORKSで発行されたサーバーIDなど

事前に用意されているのは、こちらのパラメータ である。

3. ヘッダとペイロードを . (ドット) で結合し、署名なしTokenを生成する

eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiJiYTY3M2ZhOTBiNjQ0YWU2OGI4MjliNzIxM2MxMjFkYiIsImlhdCI6IDE2MDkyNzQwMjcsICJleHAiOiAxNjA5Mjc1ODI3fQ==

4. 署名なしTokenに対し、秘密鍵を用いて署名を生成する

openssl dgst電子署名を生成する。

$ echo -n 'eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiJiYTY3M2ZhOTBiNjQ0YWU2OGI4MjliNzIxM2MxMjFkYiIsImlhdCI6IDE2MDkyNzQwMjcsICJleHAiOiAxNjA5Mjc1ODI3fQ==' | \
openssl dgst -sha256 -sign private_20201229171641.key -binary | \
base64
W//2sawtLzg3GfH6GkeS1nw947ec5qiynl2pibztjVycpe73KcENXt6Z4aftfUgMEjHRvX3N8i754E9rBffI4gfarQzY+nhUVdxP9zFXSxr7YPXoPx9A9bL4bjNRvkKJV2BRLlJkOQ6g9TY1Uu5mtPsyTZ6zy2+hXa8h8tn0dSfsLF4uH0nOiEt6p44tNz6U8/0jUlPNd3tt3W7F4MZy038nMazYQ6g5e1W7tfgqCtV0NVQUGpZdKKh0HvWf8qiqE5cTJ6y+eREENZMAEjPY6rxx19PVix1tipZ18MYm1MpCAAzFhZFXsOU+/FK295/tvIJ3g6ehgU7cHRraiGQzbg==

5. 署名なしTokenと署名を . (ドット) で結合する

eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiJiYTY3M2ZhOTBiNjQ0YWU2OGI4MjliNzIxM2MxMjFkYiIsImlhdCI6IDE2MDkyNzQwMjcsICJleHAiOiAxNjA5Mjc1ODI3fQ==.W//2sawtLzg3GfH6GkeS1nw947ec5qiynl2pibztjVycpe73KcENXt6Z4aftfUgMEjHRvX3N8i754E9rBffI4gfarQzY+nhUVdxP9zFXSxr7YPXoPx9A9bL4bjNRvkKJV2BRLlJkOQ6g9TY1Uu5mtPsyTZ6zy2+hXa8h8tn0dSfsLF4uH0nOiEt6p44tNz6U8/0jUlPNd3tt3W7F4MZy038nMazYQ6g5e1W7tfgqCtV0NVQUGpZdKKh0HvWf8qiqE5cTJ6y+eREENZMAEjPY6rxx19PVix1tipZ18MYm1MpCAAzFhZFXsOU+/FK295/tvIJ3g6ehgU7cHRraiGQzbg==

これで完成である。

上記をまとめると、以下のようになる。

$ header=`echo -n '{"alg":"RS256","typ":"JWT"}' | base64`
$ claim=`echo -n '{"iss":"ba673fa90b644ae68b829b7213c121db","iat": 1609274027, "exp": 1609275827}' | base64`
$ signature=`echo -n $header.$payload | openssl dgst -sha256 -sign private_20201229171641.key -binary | base64`
$ echo $header.$claim.$signature

この処理を簡単に実装できるのが、pyjwt というライブラリである。

pyjwt.readthedocs.io

とても使いやすく、わかりやすかった。本当に感謝である。

(おまけ)Power Automate の設定

とても簡単に連携の設定ができたので、こんなこともできるのかと、誰かの参考になれば嬉しい。

今回は、カレンダーに入っている予定の内「打ち合わせ」をタイトルに含んでいた場合は、その予定表のリンクを LINE BOT に通知してもらうようにした。ノーコードで細かく色々と設定できるのは本当に使いやすいと思えた。設定に関しては、言葉で説明するより、実際に画面をみてもらう方が早いと思うので、参考までに共有しておく。(「予定しているイベントが間もなく開始されるとき (V3)」というトリガーのお陰で、本当に簡単に実装することができた。)

f:id:serip39:20201230074254p:plain

まとめ

今回は、LINE WORKS の BOTAPI を試してみた。JWT でのToken リクエストに関しても、理解を深めることができた。

それでは、ステキな開発ライフを。