PythonでLINEログインを実装

[LINE Developersのプロダクト](https://developers.line.biz/ja/)の一つである「[ウェブアプリにLINEログインを組み込む](https://developers.line.biz/ja/docs/line-login/web/integrate-line-login/#id-tokens)」をPythonで実装してみました。

こんな感じにできます。
![](https://i.gyazo.com/d189766dcd0fd4113727d7f3e5c30acf.gif)

|LINEのAPIの過去の実装記事|
|:---:|
|[PythonでLINEの「Messaging API」でテンプレートメッセージを実装してみた](https://qiita.com/kotamatsuoka/items/c4e651f1cb6c4490f4b8)|
|[PythonでLINEの「Messaging API」のクイックリプライの解説と実装](https://qiita.com/kotamatsuoka/items/55dcbcd1b220e0d80f03)|
|[PythonでLINE Bot APIを使ってLINEユーザー情報を取得する](https://qiita.com/kotamatsuoka/items/472b455e5f9a6315d499)|
|[PythonでLINE Bot APIを使ってプッシュ通知を実装する](https://qiita.com/kotamatsuoka/items/6f56d0d0a3225160b4d0)|


## 目次
- LINE Developersのページに沿って設定
    - チャネルを設定する
- 実装
    - 認可を要求する
    - アクセストークンを取得する
    - IDトークンをデコードする
- テンプレートを用意
- おまけ

## 対象
- pythonでLINEログインを実装したい人

## LINE Developersのページに沿って設定
まず、[LINEログイン](https://developers.line.biz/console/register/line-login/provider/)内に新しいチャネルを作成します。

### チャネルを設定する
必要事項を入力して、チャネルを作成したら、ユーザがログイン後のリダイレクト先を設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/185039/78c347ed-04fc-2679-892a-040651b204c3.png)

## 実装
「[ウェブアプリにLINEログインを組み込む](https://developers.line.biz/ja/docs/line-login/web/integrate-line-login/)」ページ内に実装フローが乗っているので、その流れに沿って実装します。

### 認可を要求する

```python:app.py
@app.route("/line/login", methods=["GET"])
def line_login():
    # 認可コードを取得する
    request_code = request.args["code"]
```

### アクセストークンを取得する
「LINE_CHANNEL_ID」「LINE_CHANNEL_SECRET」は、自身のチャネルのページに記載してあるので、コピペしてください。

```python:app.py
LINE_CHANNEL_ID = "自身のチャネルID"
LINE_CHANNEL_SECRET = "自身のチャネルシークレット"
REDIRECT_URL = "設定したリダイレクト先のURL"

@app.route("/line/login", methods=["GET"])
def line_login():
    # 認可コードを取得する
    request_code = request.args["code"]
    uri_access_token = "https://api.line.me/oauth2/v2.1/token"
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    data_params = {
        "grant_type": "authorization_code",
        "code": request_code,
        "redirect_uri": REDIRECT_URL,
        "client_id": LINE_CHANNEL_ID,
        "client_secret": LINE_CHANNEL_SECRET
    }

    # トークンを取得するためにリクエストを送る
    response_post = requests.post(uri_access_token, headers=headers, data=data_params)
```

### IDトークンをデコードする

```python:app.py
LINE_CHANNEL_ID = "自身のチャネルID"
LINE_CHANNEL_SECRET = "自身のチャネルシークレット"

@app.route("/line/login", methods=["GET"])
def line_login():
    # 省略

    # トークンを取得するためにリクエストを送る
    response_post = requests.post(uri_access_token, headers=headers, data=data_params)
    # 今回は"id_token"のみを使用する
    line_id_token = json.loads(response_post.text)["id_token"]

    # ペイロード部分をデコードすることで、ユーザ情報を取得する
    decoded_id_token = jwt.decode(line_id_token,
                                  LINE_CHANNEL_SECRET,
                                  audience=LINE_CHANNEL_ID,
                                  issuer='https://access.line.me',
                                  algorithms=['HS256'])

    return render_template("line_success.html", user_profile=decoded_id_token)
```

### 他のコントローラの実装

```python:app.py
import json
import requests
import jwt
from flask import Flask, request
from flask import render_template


app = Flask(__name__)
app.config["SECRET_KEY"] = "sample1216"

LINE_CHANNEL_ID = "自身のチャネルID"
LINE_CHANNEL_SECRET = "自身のチャネルシークレット"
REDIRECT_URL = "設定したリダイレクト先のURL"

@app.route("/", methods=["GET"])
def index():
    return render_template("index.html",
                           random_state="line1216",
                           channel_id=LINE_CHANNEL_ID,
                           redirect_url=REDIRECT_URL)


@app.route("/line/login", methods=["GET"])
def line_login():
    # 省略

if __name__ == '__main__':
    app.run(debug=True)
```

## テンプレートを用意

### ディレクトリ構造
テンプレートを追加する前に、ディレクトリ構造も載せておきます。

```
LINE_login
├── app.py
├── static
│   └── LineLoginButtonImage
│       └── images
└── templates
    ├── index.html
    └── line_success.html
```

LINEから無料でダウンロードできる画像をしようして、ログインボタンを作っています。
[こちら](https://developers.line.biz/ja/docs/line-login/login-button/)からダウンロードできます。

```html:templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ログイン</title>
</head>
<body>

<h2>ログイン</h2>

<a href="https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id={{ channel_id }}&redirect_uri={{ redirect_url }}&state={{ random_state }}&scope=openid%20profile">
    <img src="{{ url_for('static', filename='LineLoginButtonImage/images/DeskTop/2x/32dp/btn_login_base.png') }}"></a>

</body>
</html>
```

```html:templates/line_success.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ user_profile["name"] }}</title>
</head>
<body>

<h2>{{ user_profile["name"] }}</h2>
<h3>ユーザID:{{ user_profile["sub"][:5] }}...</h3>
<img style="border-radius:50%;width:200px;height: 200px" src="{{ user_profile['picture'] }}"/>

</body>
</html>
```


## おまけ
最後までお付き合いいただき、ありがとうございました。
少しでもお役に立てたのであれば、嬉しいです。

以前に実装したMessaging APIの内容も含めたLINE Botの例です。ぜひ、使って遊んでみてください。
<a href="https://line.me/R/ti/p/%40qfx3178y"><img height="36" border="0" alt="友だち追加" src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png"></a>
計画・企画を多様な人から意見を聞けるサービス「[Renttle](https://renttle.jp)」を開発中です。ぜひ、使ってみて、レビューをください。