LINE Messaging API の利用におけるチャネルアクセストークンv2.1を発行

# Messaging API の利用におけるチャネルアクセストークンv2.1を発行

- 概要
  - Line のボット開発を行なっていく中で Messaging API を使用すると思います。その中で「チャネルアクセストークンv2.1」なるトークンの発行方法が割と手順が多めだったので、公式に沿って作成した手順をスクリプトなどでまとめました。

- 前提条件
  - PC：Macを使っています
  - スクリプトの実行言語としてPythonを使用しています
  - トークンの発行には専用のライブラリを使用すると楽と公式に記載があった物を使用しています 

## 手順

- [公式の手順](https://developers.line.biz/ja/docs/messaging-api/generate-json-web-token/#page-title)に沿ってやっていきます。
- [リポジトリ](https://github.com/Kyohei-takiyama/line-messaging-api)を用意しています。リポジトリ内にMakefileなどのスクリプトがあるので、適宜Cloneやコピーして使っていただくと楽だと思います
- 下記手順は、リポジトリに沿って行なっていきます(以下の手順はリポジトリのREADME.mdにも記載があります)

### アサーション署名キーを発行する
- https://developers.line.biz/ja/docs/messaging-api/generate-json-web-token/#create-an-assertion-signing-key
- JWCrypto（Pythonのライブラリ）でキーペアを生成する
- Pythonファイルを作成します
    
    ```python main.py
    from jwcrypto import jwk
    import json
    key = jwk.JWK.generate(kty='RSA', alg='RS256', use='sig', size=2048)
    
    private_key = key.export_private()
    public_key = key.export_public()
    
    print("=== private key ===\n"+json.dumps(json.loads(private_key),indent=2))
    print("=== public key ===\n"+json.dumps(json.loads(public_key),indent=2))
    ```
    
    ```sh
    # Makefileを作成しているので、下記コマンドで一撃
    make run
    ```
- 秘密鍵と公開鍵のキーペアが作成される
  - 下記のように出力されているはず。キャプチャの例は[公式](https://developers.line.biz/ja/docs/messaging-api/generate-json-web-token/#use-python)から拝借。
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/deceb50f-4f7d-aeec-cd78-72253cb45245.png)

  - 公開鍵部分のJSONをコピーしておく

### Kidを取得する
- 公開鍵を登録する
  - 公式にのっとります
    - ［チャネル基本設定］タブをクリック
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/83786438-f732-4b2a-f039-229b96b0d893.png)

    - 次に、アサーション署名キーの横にある［公開鍵を登録する］ボタンをクリック
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/70bfc5f5-50f7-98ed-3b16-ba4ad3203c2c.png)

    - 公開鍵を入力し、［登録］ボタンで登録を確定します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/089f245a-033c-3b7d-ca56-511338e02668.png)

    - kid が発行してコピーしておく
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/6bb47cb8-02cf-fbf2-3c3e-6ebd7db326aa.png)


### JWTを生成する
- PyJWT（Pythonのライブラリ）でJWTを生成していきます
- Pythonファイルは公式を参考に作成してあります。
- チャンネルIdの場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/5cf1122e-50b3-add8-3a61-9e051fd2732b.png)

    
    ```python issue_jwt.py
    import jwt
    from jwt.algorithms import RSAAlgorithm
    import time
    
    # ============= 出力した自分の秘密鍵をコピーして貼り付ける
    privateKey = {
      "alg": "RS256",
      "d": "*******************",
      "dp": "*******************",
      "dq": "*******************",
      "e": "*******************",
      "kty":"*******************",
      "n": "*******************",
      "p": "*******************",
      "q": "*******************",
      "qi": "*******************",
      "use": "sig"
    }

    # ============= kidを入れます
    headers = {
        "alg": "RS256",
        "typ": "JWT",
        "kid": "*******************",
    }
    
    # ============= ここにChannel IDを入れる
    payload = {
      "iss": "**********", # Console から Channel ID を取得
      "sub": "**********", # Console から Channel ID を取得
      "aud": "https://api.line.me/",
      "exp":int(time.time())+(60 * 30),
      "token_exp": 60 * 60 * 24 * 30
    }
    
    key = RSAAlgorithm.from_jwk(privateKey)
    
    JWT = jwt.encode(payload, key, algorithm="RS256", headers=headers, json_encoder=None)
    print(JWT)
    ```

    ```sh
    # 下記のMakeコマンドでJWTが出力される
    make issue-jwt
    ```
- 出力されたJWTが正しいかどうかはJWTの公式サイトでデコードして確認する
https://jwt.io/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3531653/41175571-3934-9a1e-60d5-415a9bdcfdac.png)


### チャネルアクセストークンv2.1を発行する
- 公式のサンプルでPostします。curlコマンドがない方はPostmanなどでリクエストを送信すると良いと思います。

```sh
# {JWT}の部分を丸ごと発行したJWTで書き換えてください
curl -v -X POST https://api.line.me/oauth2/v2.1/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion={JWT}'

# ↓↓↓↓↓↓↓↓↓↓↓↓ 実行後 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓

# こんな感じでチャネルアクセストークンとキーIDのペアが帰って来れば成功です！
{
	"access_token": "************",
	"token_type": "Bearer",
	"expires_in": 2592000,
	"key_id": "********"
}
```

## まとめ

Messaging APIを使用するための「チャネルアクセストークンv2.1」の発行手順をスクリプトで簡略化てまとめてみました。
手順は公式ドキュメントに沿っております。
公式ドキュメントはわかりやすいのですが、割と手順が多くて次やる時に「うっ」ってなってしまウト思ったためまとめました。
どなたかの一助になれば幸いです。