# チャネルアクセストークンv2.1を発行する

ここでは、アサーション署名キーからJSON Web Token(JWT)を生成する方法と、生成したJWTを使ってチャネルアクセストークンv2.1を発行する方法について説明します。

# アサーション署名キーを発行する

LINE Developersコンソールのチャネル設定からMessaging APIチャネルを選択して、チャネル基本設定タブにアクセスします。次に、アサーション署名キーの横にある[発行]ボタンをクリックして、アサーション署名キーを発行します。チャネルごとに最大2つのキーペアを作成できます。

アサーション署名キーが発行され、秘密鍵がダウンロードされます。秘密鍵は、必ず安全な場所に保管してください。

鍵の保管について

LINEは公開鍵のみを保管します。秘密鍵は保管しません。秘密鍵は必ず各自で保管してください。秘密鍵は発行時に一度だけ表示されます。

# JWTを生成する

JWTを生成するには、任意のJWTライブラリ (opens new window)を使用することもできますし、アサーション署名キーを使って独自のコードをスクラッチで書くこともできます。

ここでは、JWT (opens new window)で紹介されているJavaScriptライブラリを使用して作成する例を説明します。ここで説明するコードを使用するには、事前に以下をインストールする必要があります。

JWTは、ヘッダー、ペイロード、署名からなる文字列です。すべての項目が必須フィールドです。

ヘッダー

プロパティ 説明
alg 固定プロパティ:RS256
typ 固定プロパティ:JWT
kid アサーション署名キーを作成する」でダウンロードした秘密鍵のkidプロパティの値を使用します。

以下は、ヘッダーの値をデコードした例です。

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "536e453c-aa93-4449-8e90-add2608783c6"
}

ペイロード

プロパティ タイプ 説明
iss String チャネルID。LINE Developersコンソールで確認できます。subと同じ値にします。
sub String チャネルID。LINE Developersコンソールで確認できます。issと同じ値にします。
aud String https://api.line.me/
exp Number JWTの有効期間。UNIX時間で設定します。JWTアサーションの最大有効期間は30分です。
token_exp Number チャネルアクセストークンを要求するときに必要です。チャネルアクセストークンの有効期間を秒単位で設定します。チャネルアクセストークンの最大有効期間は30日です。

以下は、デコードされたペイロードの例です。

{
  "iss": "1234567890",
  "sub": "1234567890",
  "aud": "https://api.line.me/",
  "exp": 1559702522,
  "token_exp": 86400
}

署名

アサーション署名キーの秘密鍵で、上記のようなヘッダーとペイロードを署名することでJWTが生成できます。

node-joseを使って秘密鍵で署名してJWTを生成するコードの例です。このコードを使って自分のJWTを作成する場合は、privateKeyを自分のアサーション署名キーの秘密鍵の値に変更し、headerpayloadの値をそれぞれ変更してから実行します。node-joseの使い方について詳しくは、node-jose (opens new window)を参照してください。内容が改ざんされていないことを証明するために、必ず秘密鍵で署名を行います。

node-joseを使ったコードの例

let jose = require('node-jose');

let privateKey = `
{
    "p": "4h8yEw4q9VkzhXMgXZsIZVkEuZ49EmtWYk9zs0hPTa24ejjRMA6KTYh_va0GlaChO9t0MVQVuduznt-OFZyRAinr4svU4MKD2A3gTHJJCxs0xICva8rkHXqxfPwXngpb5L_xFURbXcSTzMcKckWuOpyPznAgY4XsZxw0t7ewj9E",
    "kty": "RSA",
    "q": "pVhBdRN5K3MEiZzU4__TsrtSBJDD_stu60m73iIvsHIrvK3Dmfl-J1zhsyOvi3NH9mVXpUimBwP8nTe-BlVM71G7_EotFHeKH1zTmBlx6AOngmrc40W2Hd__OZW0NfC_xOTvI_Ea2BNGoGtcrIGVFLTivJ4y9wAVOKA058zJ0ls",
    "d": "ObzE_-TROJazDm-ry-8TKRBMGzwcwTK6lMFSk7n-Xp6h7cDauSdRRYnZivC1lh5plVG3I9aUmPTRbVk7nrPqOlp4WWKQ27lyLd5IogbArpXgnBSkp9Zy0lWzvOsI3gHNnYuehyksHB53FIK93t838JfDQoXUUzalNoNwAGfkTNZxT4GIXGMGzNck2Z_urOATMf8-wdad-u4a5IB2KfHugwH2kw-Zig7fbdcN4_DeKWpuigdesa48Yj_hRJRws-mVFp-xHlGJehumnM_v8FLD85ap8L1hwvBqdJQeurcLXYzZbtdp9a5GpJI7gzOTMoEdxIKlEIIbaOKv4rkkztdhoQ",
    "e": "AQAB",
    "use": "sig",
    "kid": "536e453c-aa93-4449-8e90-add2608783c6",
    "qi": "XQ2puK9LT5yimyJXlXb4nHEBzPGe3sYbaZW_gMK4iHuM8cseImwLNP8ZIeGaNx5X_hZ6ZOzkjtYJjY85fvaWa2UDGdGlEw3ZO-Nk0Qu_exBrqZgZAsua75TjpJRw01Yd1TNBx5MYuvhltJLsjW-uSjcE-rZoO74FEe9pYYeQjI4",
    "dp": "Qq_wlK4Y_ULRbwoFAZY3Y6xdOGDyofwF_fhwpu8sdDxHq8QV7ZZcM4GOKuJcjsRQyNZv7hxeS_H_h1tnC_igy4KRjtGOdrrnJ1DwVZte72eWqF1LXv73R7pnnfS7AmELuOriruL6Dy1qaXpKGmlyeNazkq5-3tsgXUh0Q7po2AE",
    "alg": "RS256",
    "dq": "Wj1ovDT8lLIZb-Ggby9YotuJT-SSk6UDzHZZikquLGajaD6N2qNILsOKivKXBEzOobN9uj-EHaAXZtbdZyd27cZ2CqORJvJ299b5xLFecXpNGeio1YFee7-c1BjYWfgjMZqgycT1GairizINSjkO3FY8ySSuPBBXhKgrN7eVDrE",
    "n": "kgwP0NPaoAwhSh9iLlRaT7FSRbNsl6T5-j-bB3xAT1UbsxOJ9v06S3_54bpYlEAkjlrO-i1vmSzfSVnqFXnjWThWRvPmBDth3Ka7hQm9UXjiAvTzYxXGFjyhALqa_-DQCtdrqIhi8E4hAuSu--kGgnFKg3G-21KJuqnVzsXrClGkxbmVufx0MJjJxr1YGfkTMG8i0dovS9tnkioDAkt1knupiYk5ir_WiNy4T-70T5s3ktC5_4Uz10hS-rWeUxiihzG8G7ceg84-Kt5jKP_AgUnel-ksRyfgSJCYC9nHyz913a3ALj3Dzt7TBaxwAjlxESrdNz5RE9DNDZfPmNWRSw"
  }
`;

let header = {
    alg: "RS256",
    typ: "JWT",
    kid: "536e453c-aa93-4449-8e90-add2608783c6"
};

let payload = {
    iss: "1234567890",
    sub: "1234567890",
    aud: "https://api.line.me/",
    exp: Math.floor(new Date().getTime() / 1000) + 60 * 30,
    token_exp: 60 * 60 * 24 * 30
};

jose.JWS.createSign({format: 'compact', fields: header}, JSON.parse(privateKey))
    .update(JSON.stringify(payload))
    .final()
    .then(result => {
        console.log(result);
    });

Base64形式でエンコードされたヘッダーとクレーム・セット、および秘密鍵(rsa_private.pemファイルなど)を、ヘッダーで定義したアルゴリズムを使用して署名します。署名後、Base64形式でエンコードされた結果がJWTになります。

エンコードされたJWTの例

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjJjNjU4NWYzLThkZGQtNDZjNC05YmUyLWI1NGE3MGFhOTRlYSJ9.eyJpc3MiOiIxNjUzOTQ3MTcyIiwic3ViIjoiMTY1Mzk0NzE3MiIsImF1ZCI6Imh0dHBzOi8vYXBpLmxpbmUubWUvIiwiZXhwIjoiMTU4NTIwMDA2MiIsInRva2VuX2V4cCI6IjI1OTIwMDAifQ.UVG6PAEub-OPbZ3nJuVxRRPjY6Sz_eIHJV9DTTAHCR79YsG4yWvoa9AeIctibb6IJQKgTEV7mF7LsUDmXldEDqYwyEmKs38zj_995Ntc9SYBFphHpr09NqfMoqMphwKqms2NOnqgcHreFs27d9Q0Qv8Rtv2t7SB2cVO__KrsjzYNs3miTvDdkqYLXFo5fXwuzNtHOCAJomd6bhMR8Yd1-vJmtMCBPK4hmA98w8fG_NhcyLbw-B9AuxQ6z92zXiRhNyPlK_3ce2T7HtgUluJ4xJl4xdLJ_C6hvTAqtQxmSiJKzbjUiANF6hVBTomU8vkaIjEKjnlT1uPMihfrsA3pzQ

# チャネルアクセストークンv2.1を発行する

JWTを生成する」の手順で生成したJWTアサーションを指定して、チャネルアクセストークンv2.1を発行できます。

キーIDを使ってチャネルアクセストークンv2.1を管理する
  • チャネルアクセストークンv2.1発行時のレスポンスには、チャネルアクセストークンとペアになる一意のキーID(key_id)が含まれます。チャネルアクセストークンを正しく管理するために、必ずチャネルアクセストークンとキーIDをペアで保管するようにしてください。
  • キーIDは、2020年6月22日のMessaging APIのアップデートで追加された識別子です。キーIDを持たないチャネルアクセストークンv2.1をお使いの場合、チャネルアクセストークンv2.1を再発行し、トークンとキーIDのペアを保管することをお勧めします。チャネルアクセストークンを再発行した場合は、必ず新しいトークンを使うようにボットを改修してください。

Store the pair of issued access tokens and key ids

  1. 生成したJWTを指定して、チャネルアクセストークンv2.1を発行するエンドポイントを実行し、チャネルアクセストークンを発行します。
  2. チャネルアクセストークンキーIDがLINEプラットフォームから返ります。
  3. チャネルアクセストークンキーIDをペアにしてデータベースなどに保管します。

# チャネルアクセストークンv2.1を取り消す

チャネルアクセストークンv2.1を取り消すエンドポイントを実行することでチャネルアクセストークンを取り消すことができます。

有効なチャネルアクセストークンの識別

無効なチャネルアクセストークンを指定して、チャネルアクセストークンv2.1を取り消すエンドポイントを実行した場合も、エラーレスポンスは発生しません。すべての有効なチャネルアクセストークンv2.1のキーIDを取得するエンドポイントを使って、現在有効なチャネルアクセストークンとペアになるキーIDを取得できます。取得したキーIDを、データベースなどに保管したチャネルアクセストークンとキーIDのペアと照合することで、有効なチャネルアクセストークンを識別できます。

Store the pair of issued access tokens and key ids

  1. 保存したアサーション署名キーからJWTを再生成します。
  2. JWTを使ってすべての有効なチャネルアクセストークンv2.1のキーIDを取得するエンドポイントを実行します。
  3. 有効なチャネルアクセストークンキーIDがLINEプラットフォームから返ります。
  4. チャネルアクセストークンキーIDのペアを保管したデータベースなどを参照します。
  5. 取得したキーIDと一致する、チャネルアクセストークンキーIDのペアを検索します。
  6. 有効なチャネルアクセストークンを取得します。
  7. 有効なチャネルアクセストークンを指定して、チャネルアクセストークンv2.1を取り消すエンドポイントを実行します。
  8. LINEプラットフォームからチャネルアクセストークンが取り消されます。