Node.js による LINE WORKS トークBot 開発 | JWT 作成と access_token 発行

159
にほんブログ村 IT技術ブログへ

概要

kintone 絡みで Line WorksのトークBotを作る事になってるのですが、開発時に必要なJWT作成とaccess_token発行にハマってしまったので、作業ログとしていくつかNode.jsスクリプトを残しておきます。

最初はPowerShellでサクッと作ろうかと思ってやってたのですが、情報が少なく、サンプルも見当たらなかったのでNode.jsに切り替えましたが、それでも時間掛かった。。。

公式ページにサンプルコードが欲しかったです。。。

公式のLine Worksの開発概要はこちら

公式のトークBot開発概要はこちら

この記事で扱うのは、サーバーAPI呼び出し時に必要な access_token の発行の仕方です。

公式ページでは、こちらのAPI認証の準備におけるサーバーAPIの記述部分になります。

やりたい事

公式ページの記載を引用すると以下の事がやりたいのです。

概要図

このJWTの生成の仕方が正直言って良くわかりませんでした。。。
JWTは以下の形式にするそうなんですが、ドット区切りの3つ目のブロックで電子署名のやり方がよく分からず苦戦しました。

{header BASE64 エンコード}.{JSON Claim set BASE64 エンコード}.{signature BASE64 エンコード}

JWT生成

ネット上のサンプルを色々あさり、結果的には以下のコードでJWTは生成できました。
ほぼパクリなので参考程度にしてください。

const crypto = require('crypto')
const fs = require('fs')
const path = require('path')

const privateKeyPath = '.\\private_xxxxxxxxxxxxx.key'
const payloadServerId = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'

const base64 = json => {
    const jsonStr = JSON.stringify(json)
    const jsonB64 = Buffer.from(jsonStr).toString('base64').replace(/={1,2}$/,"")
    return jsonB64
}

const createSignature = data => {
    const sign = crypto.createSign('RSA-SHA256')
    sign.update(data)
    const privateKey = fs.readFileSync(path.resolve(privateKeyPath), "utf8");
    const signedData = sign.sign(privateKey, 'base64').replace(/={1,2}$/,"")
    return signedData
}

const header = { alg: 'RS256', typ: 'JWT' }
const startTime = new Date()
const endTime = new Date(startTime.getTime() + 1000 * 60 * 30)
const payload = {
    iss: payloadServerId,
    iat: Math.floor(startTime.getTime() / 1000),
    exp: Math.floor(endTime.getTime() / 1000)
}

const unsignedToken = `${base64(header)}.${base64(payload)}`
const signature = createSignature(unsignedToken)
const jwt = `${unsignedToken}.${signature}`

console.log(jwt)

base64エンコード時に最後に付加される==を削っているのは、JWTで生成する文字列はURLで使用して安全な文字列にするのが原則であるためです。

ただ、==が付いた状態で次の access_token 発行処理をやっても問題はありませんでした。
何故かは分かりませんが。。。

どっかで削除してくれてるのかも。。。

access_token 発行

肝心の access_token は以下のようにPOST送信で発行します。
JWTが生成できればここは問題ないです。

var request = require('request');

const bodyGrantType = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
const bodyAssertion = '(JWT)'

var options = {
    uri: 'https://auth.worksmobile.com/b/(API ID)/server/token',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    },
    form: {
        'grant_type': bodyGrantType,
        'assertion': bodyAssertion
    }
};
request.post(options, function(error, response, body){
    console.log(response.body);
});

 

4行目に前段で作成したJWTをセットします。
7行目のAPI IDはDeveloper Consoleで確認してください。

実行すると以下のように レスポンスで access_token が取得できます。

{
  "access_token":"(access_token)",
  "token_type":"Bearer",
  "expires_in":xxxxx
}

 

参考

以下、参考にさせていただいたページ。

https://qiita.com/0xfffffff7/items/e96bcebfddb4a736ffc1

https://qiita.com/tokotan/items/f615f4a62219d655436f

https://qiita.com/tokotan/items/976d35ca56132e0bb5c1

https://techblog.yahoo.co.jp/advent-calendar-2017/jwt/

以下、JWTを生成してくれるページ。便利。

https://jwt.io/

以上

wpmaster
  • wpmaster
  • フリーランスシステムエンジニアの鎌形です。
    鎌形システムエンジニアリングとして都内で活動中です。

%d人のブロガーが「いいね」をつけました。