LINE API の Web Login v2（現 LINE ログイン）導入方法（日本語訳）

この記事は **LINE Web Login（現 LINE ログイン）、俗に言う OAuth ログインの LINE 版に関する LINE API v2.0 の説明**です。 

:::note warn
<sup>🐒 &nbsp;2018/01/28 追記：元々は、去年（2017 年に）訳していた "<a href="https://developers.line.me/en/docs/line-login/web/integrate-line-login-v2/">LINE Developers - Web API - Integrating Web Login</a>" の v2 の日本語訳の記事なのですが、今年（2018 年）に入って <a href="https://developers.line.me/ja/docs/line-login/web/integrate-line-login/">LINE ログイン V2.1</a> のリリースとともに<a href="https://developers.line.me/ja/docs/line-login/web/integrate-line-login-v2/">本家で翻訳が出てました</a> (´・ω・`) 下書きの空きを作るために公開します。<del>削除に忍びない</del></sup>
<sup>また、わかりづらい用語には筆者の独断で補足および関連リンクを貼っています。「LGTM」（旧いいね）が付くたびに何かしら手を付けてますが、変更通知は送りませんのでストックされた方はお手すきに覗きに来てください。</sup>
<sup>🐒 &nbsp;2022/01/18 追記: この記事の LINE API v2.0 は廃止（<code>deprecated</code>）になりました。現在は <a href="https://developers.line.biz/en/reference/line-login/">v2.1</a> ですが、仕組みの基本は同じなので理解を深めるための参考にしてください。なお、実際に利用する場合は <code>OpenID Connect</code> の利用を検討してください。</sup>
:::

- 参考記事
  - GitHub Login も OAuth を使っているので参考になると思います。
      - [GitHub API のスコープとは](https://qiita.com/KEINOS/items/216d138b0fdf994b9582#tsdr%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97%E3%81%A8%E3%81%AF) | GitHub API v3 の Scopes と Scope 一覧 @ Qiita
  - LINE のアカウントの種類、プロバイダー、チャンネルがわかりづらい場合の参考記事
      - [LINEログインを実装するまでのメモと、LINEアカウントの種類](https://qiita.com/nowmura/items/249ce472bde742959c3a#_reference-2bfc5434ec2cf8960870) @ Qiita

▼ 以下筆者訳 ＋ <ruby>α<rt>アルファ</rt></ruby>

# Web Login を導入する

このページは LINE API の Web Login v2 を、あなたのサイトに導入する方法を説明します。Web Login v2 は [OAuth 2.0](https://tools.ietf.org/html/rfc6749) の[プロトコル](https://qiita.com/KEINOS/items/cb7f629268b90ef6493d)を基本にしています。

1. Web Login の流れ
2. LINE Login starter アプリケーション
3. 要件
4. 承認コードの取得
5. アクセス・トークンの取得
6. API の呼び出し

:::note warn
<strong>現行バージョンと廃止バージョン</strong>

このページは Web Login の最新バージョンである Web Login v2 について説明しています。非推奨となっている Web Login v1 の仕様を参照したい場合は <a href="https://developers.line.me/web-api/integrating-web-login">Web Login v1</a>（<a title="LINE Web Login 導入方法(日本語訳)" href="http://qiita.com/0918nobita/items/0a5846ac126a399210f7">日本語訳</a>）をご覧ください。

<strong>注意：</strong> Web Login v1 のサポートは 2018 年 1 月までとなっています。そのため Web Login v2 の利用が推奨されています。
:::

## Web Login の流れ（OAuth ログイン）

LINE の Web API（以下 API）を呼び出すには「アクセス・トークン[^1]」が必要です。そして、そのアクセス・トークンを取得するためには「承認コード」が必要です。

[^1]: **トークンとは**「同じコミュニティ内のみで通じる等価交換の価値がある何か」です。逆に言えば「そのコミュニティ以外では何の価値もなくなる何か」です。古代ノルド語で仲間間の「サイン」や「記号」を意味する `teikn` から来ています。<br>一般社会では、例えば遊園地で各アトラクションごとに購入するチケットや、ゲームのチップなどが該当します。Web API の場合は、数値が使われることが多く、予測を難しくするため [n 桁の 16 進数の値をハッシュ関数で作成](https://qiita.com/KEINOS/items/c92268386d265042ea16)することが一般的です。このトークンを添えて Web API にリクエスト（アクセス）して処理結果を取得するため「アクセス・トークン」と呼ばれます。<br>提示しないとアクセスできない仕組みはパスワードと似ており、特にワンタイム・パスワードに近いものです。パスワードとトークンの主な違いは、パスワードは基本的にユーザー側が任意に決められるもので、トークンはコミュニティ側が発行するなど任意に決められないものを言います。銀行でオンライン口座にアクセスする際に必要なワンタイム・パスワードを、海外では「トークン」と呼ばれるのもそのためです。

まず、あなたの Web アプリ利用者（以下ユーザー）は、あなたのウェブサイトから LINE のドメイン上の「ログイン画面」に誘導されます。ユーザは、「安全な認証」と「アプリの承認」を行うためにログインし（認証）、「あなたの Web アプリからのアクセスを許可するか」の同意（承認）を行います。

その後、ユーザーがあなたのウェブサイトに「承認コード」と一緒に転送されると、あなたの Web アプリからアクセス・トークンが取得できるようになります。

以下は API の呼び出しに必要なアクセス・トークンを取得する主な流れです。（より具体的な流れは後述します）

1. あなたは「LINE ログイン」用のリンクを用意してウェブサイト（Web アプリ）に設置します。
2. ユーザーはリンクを開くと、あなたのウェブサイトから LINE の「ログイン画面」に転送され、LINE にログインします。
3. ユーザーは、あなたのウェブサイトがそのユーザーの LINE アカウントの情報にアクセスすることに同意（許可/承認）します。
4. 同意後、「承認コード」と共にユーザーは、あなたのウェブサイトに逆転送されます。（これをコールバックと言います）
5. 転送先の、あなたのウェブサイトのページでは URL に含まれる「承認コード」を確認します。
6. あなたのウェブサイトから LINE の承認サーバーに、上記の「承認コード」を送りアクセス・トークンを要求します。
7. LINE の承認サーバーは整合性を検証しアクセス・トークンを返します。
8. あなたのウェブサイトは、取得したアクセス・トークンを使い、スコープ（許可された操作）の範囲内でユーザーに代わり LINE API で操作を行います。

ご覧のように、上記は一般的な OAuth によるアクセス・トークン取得までの仕組みです。

つまり 1〜5 までのステップで「承認コード」、もしくは 1〜7 までのステップで「アクセス・トークン」を取得できたということは LINE のログイン・プロセスをパスしてきたということです。

この<strong>「アクセス・トークン」を取得できた時点で「ユーザーはログイン認証された」と見なす</strong>ことで、「LINE の認証によるログイン」を実現します。これを LINE Web Login（以下 Web Login）と言います。

> <sup>🐒 &nbsp; LINE に限らず、このようなプロセスを経てログインとみなすログイン認証を「OAuth ログイン」と呼びます。つまり `LINE Web Login v2` は LINE の OAuth ログインということです。</sup>

## Line Login Starter アプリケーション

LINE Login Starter アプリケーションを利用すれば Java で簡単に LINE Login を試せます。LINE Login Starter アプリケーションを使うには下記の GitHub のリポジトリをご覧ください。

- [LINE Login Starter Application](https://github.com/line/line-login-starter) | Line @ GitHub

## LINE Web Login の要件

Web Login をあなたのウェブサイトに導入するためには事前に LINE にアプリの登録が必要です。LINE の [console](https://developers.line.biz/console/register/line-login/channel/) からチャンネルを作成し、以下の情報の登録および取得が必須です。

- **Channel ID：** あなたのチャンネル登録時に発行された ID。
- **Chennel secret：** あなたのチャンネル登録時に発行された秘密鍵。
- **Callback URL：** 認証後の転送先 URL の事前登録。複数の URL を登録できます。

## 承認コードの取得

Web Login をあなたのウェブサイトに導入するにあたり、まずは承認コードを取得する必要があります。のちにアクセストークンを取得するのに必要だからです。

### ログイン（認証と承認リクエスト）

承認コードを得るためには、ユーザーに「ログイン」リンクやボタンを押させ LINE の「ログイン画面」に転送させる必要があります。この時の LINE の「ログイン画面」への転送先 URL の構成は以下の通りです。

```bash:１行表記
https://access.line.me/dialog/oauth/weblogin?response_type=code&client_id={Channel ID}&redirect_uri={Callback URL}&state={State}
```
```php:複数行表記
https://access.line.me/dialog/oauth/weblogin \
  ?response_type=code \
  &client_id={Channel ID} \
  &redirect_uri={Callback URL} \
  &state={State}
```

#### クエリのパラメーター
| パラメータ名 | 値 | データ型 | 必須 | パラメータ名<br>説明 |
| :-----: | :-----: | :-----: | :-----: | :----- |
| response_type | *code* | String | 必須 | **`response_type`**<br>値は "code" です。これにより、LINE の承認サーバーに承認コードを返すように伝えます。 |
| client_id | Channel ID | String | 必須 | **`client_id`**<br>LINE で発行された Channel ID |
| redirect_uri | Callback URL | String | 必須 | **`redirect_uri`**<br>認証と承認の後、処理をウェブサイトに戻すためにリダイレクトする URL。登録した Chennel の管理画面で予め登録しておく必要があります。 |
| state | 何かしらの英数字の文字列 | String | 必須 | **`state`**<br>一意のランダムな文字列。Callback URL に転送されたときに使われます。URL エンコードをしてはいけません。下記の注釈を参照してください。 |

**注釈：** [クロス サイト リクエスト フォージェリ](https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA)（CSRF）の脅威を避けるため、対策として LINE の「ログイン画面」への転送 URL（承認リクエスト URL）の生成時にランダムで一意の値を "state" パラメーターにセットし、転送の前後のセッション内で統合を行なってください。"state" パラメーターが設定されていない場合、自動ログインは動作しません。

#### ログイン認証のサンプルURL
以下は LINE の「ログイン画面」で認証と承認を行う URL のサンプルです。

```bash
https://access.line.me/dialog/oauth/weblogin?response_type=code&client_id=12345&redirect_uri=https%3A%2F%2Fsample.com%2Fauth&state=123abc
```
```php
https://access.line.me/dialog/oauth/weblogin
  ?response_type=code
  &client_id=12345
  &redirect_uri=https%3A%2F%2Fsample.com%2Fauth
  &state=123abc
```

### レスポンス（コールバック）

ユーザーが LINE のログイン認証と承認を行うと、ユーザーは認証のリクエストの URL でクエリに指定された URL（つまり `redirect_uri` パラメーターの URL ）へ転送されます。その際に、正常に認証および承認が行われた場合は以下のパラメーターを含んだクエリ付きで転送されます。

| パラメータ名 | データ型 | パラメータ名<br>説明 |
| :-----: | :-----: | :----- |
| code | String | 結果を出力しアクセストークンを発行するために必須な文字列です。認証コードは 10 分間有効です。 |
| state | String | 認証と承認リクエスト時に指定された `state` パラメータの文字列です。 |

#### レスポンスのサンプル

認証および承認が正常に行われた場合、ユーザーは `code` および `state` パラメーターのクエリ付きで、リクエスト時に指定した `redirect_uri` の URL に転送されます。以下はレスポンス（コールバック）のサンプルです。

```
https://sample.com/auth?code=b5fd32eacc791df&state=123abc
```

#### エラー時のレスポンス（承認拒否時）

ユーザーが LINE にログイン（認証）後、ウェブサイトからのアクセスを許可（承認）しなかった場合は、以下のパラメーター付きのクエリでウェブサイトに転送されます。

| パラメータ名 | データ型 | パラメータ名<br>説明 |
| :-----: | :-----: | :----- |
| error_description | String | **`error_description`**<br>値は "The+user+has+denied+the+approval" です。**注釈:** このパラメーターは、iOS および Android アプリのアプリ内ブラウザには現れません。現在この問題は対策中です。 |
| errorMessage | String | "DISALLOWED" |
| errorCode | Integer | "417" |
| state | String | 認証と承認リクエスト時に指定された `state` パラメータの文字列です。|
| error | String | "access_denied" |

#### エラーレスポンスのサンプル

以下は認証および承認リクエストで承認されなかった（エラーがある）場合に、転送される URL のサンプルです。

```
https://sample.com/{Callback URL}?error_description=The+user+has+denied+the+approval&errorMessage=DISALLOWED&errorCode=417&state=[state]&error=access_denied
```

## アクセス・トークンの取得

### APIの呼び出し


> OAuth 2.0 の仕様
最新の Web Login の特徴は OAuth 2.0 の仕様に基づいています。もし非推奨の Web Login の仕様について知りたい場合は [(Deprecated) Integrating Web Login](https://developers.line.me/web-api/deprecated-integrating-web-login) を参照してください。

### 導入の手順

API を利用するためにはアクセストークンが必要です。安全に認証を行うために LINE のログイン・許可のためのページに移動し、認証の後、あなたのウェブサイトにリダイレクトしアクセストークンを取得できます。手順は以下のようになります。

1. LINE のサイトに移動する
2. ログイン・PIN コード認証・許可画面が表示され、ユーザーが必要事項を入力し許可する
3. 認証コードとともにウェブサイトにリダイレクトする
4. アクセストークンを取得するためにウェブサイトのサーバーから LINE のサーバーに認証コードが送られる
5. アクセストークンは API を利用するために用いられる

### 前提条件

ウェブサイトに LINE Web Login を導入するために、以下の情報が指定されなければなりません。

- Channel
- Channel Secret
- Redirect URL

Channel ID と Channel Secret は、登録作業中に発行される識別子です。LINE のサイトでログイン・許可した後、処理がウェブサイトに戻ります。安全のために、LINE Developers でリダイレクトページを指定しなければなりません。複数のリダイレクトページを登録できます。この情報はチャンネルの作成処理中に段階を踏んで登録されます。

### 認証コードを取得する

ウェブサイトに LINE Web Login を導入する前に、認証コードを取得する必要があります。認証コードの取得方法は以下の通りです。

### ログイン画面

LINEログインボタンが押されたとき、認証と承認のために LINE のログイン画面にリダイレクトします。その URL は以下の通りです。

```
https://access.line.me/dialog/oauth/weblogin?response_type=code&client_id={Channel ID}&redirect_uri={Redirect URL}&state={State}
```
```
https://access.line.me/dialog/oauth/weblogin
  ?response_type=code
  &client_id={Channel ID}
  &redirect_uri={Redirect URL}
  &state={State}
```

パラメータは以下の通りで、すべて明記されなければなりません。

| パラメータ名 | 値 | データ型 | 説明 |
| :-----: | :-----: | :-----: | :----- |
| response_type | ``code``で固定 | String | 必須 |
| client_id | Channel ID | String | LINE で発行された Channel ID |
| redirect_uri | Redirect URL | String | 認証と承認の後、処理をウェブサイトに戻すためにリダイレクトする URL |
| state | 何かしらの英数字の文字列 | String | 任意です。Redirect URL にリダイレクトしたときに使われます。URL エンコードをしてはいけません。注釈を参照してください。 |

リダイレクト URL はチャンネル登録時に指定した URL と一致していなければなりません。比較対象は URL のスキーム(`http` や `https`)からパス名(ディレクトリ名やファイル名)まで(要は GET パラメータより前の部分)で、パラメータの部分は比較対象にはなりません。パラメータの値は URL エンコードして指定してください。`state` パラメータについては、文字列がリダイレクト URL にそのまま付与されます。

`state` パラメータはウェブサイトのセッションを維持するために使用され、CSRF 対策にも有効です。セッションに対応した文字列が `state` パラメータの値のように指定されます。

リダイレクト URL に付与される `state` パラメータの値に関しては、ウェブサイト上でセッションに対応しているかどうかに応じて、その文字列は正しいことが確かめられます。そうすることで、同じ個人として LINE Web Login を導入するためにウェブサイトのユーザーと、認証と承認を行ったユーザーを識別することが可能になります。

**注意**
`state` パラメータの文字列は LINE のページからリダイレクトする時に URL デコードされるので、URL エンコードされた文字列を使わないでください。これは既知の問題で、`state` パラメータが OAuth 2.0 プロトコルで指定されたように変わらずリダイレクト URL に付与されるために、私達はその修正を進めています。

### ウェブサイトにリダイレクトする

認証と承認は一度だけ行われ、LINE のページから指定された URL にリダイレクトします。結果はパラメータで与えられます。成功すると以下のパラメータが付与されます。

| 名前 | データ型 | 説明 |
| ----- | ----- | ----- |
| code | String | 結果を出力しアクセストークンを発行するために必須な文字列です。認証コードは10分間有効です。 |
| state | String | 認証と承認で指定された `state` パラメータの文字列です。 |

例えば、以下のように認証と承認が行われたとします。

```
https://access.line.me/dialog/oauth/weblogin?response_type=code&client_id=12345&redirect_uri=https%3A%2F%2Fsample.com%2Fauth&state=123abc
```
```
https://access.line.me/dialog/oauth/weblogin
  ?response_type=code
  &client_id=12345
  &redirect_uri=https%3A%2F%2Fsample.com%2Fauth
  &state=123abc
```

成功したら、LINE のページから以下のページにリダイレクトします。CSRF 対策で、手続きを確かめる事が必要です。

```
http://sample.com/auth?code=b5fd32eacc791df&state=123abc
```

失敗したら、以下のパラメータが付与されます。

| パラメータ名 | データ型 | パラメータ名<br>説明 |
| :-----: | :-----: | :----- |
| errorCode | Integer | **`errorCode`**<br>どんな種類のエラーにも割り当てられる値 |
| errorMessage | String | **`errorMessage`**<br>出力されるエラーの原因 |

以下のエラーコードとエラーメッセージが返ると思われます。

| エラーコード | エラーメッセージ | 原因 |
| ----- | ----- | ----- |
| 417 | DISALLOWED | 許可ページでキャンセルボタンを押された |

上記の例では、LINE のページから以下の URL にリダイレクトします。

```
http://sample.com/auth?errorCode=417&errorMessage=DISALLOWED
```

### アクセストークンを取得する

認証と承認に成功したら、認証コードが発行されます。API を利用する上で、アクセストークンを発行するために認証コードを使用します。アクセストークンは次のようなエンドポイントで発行されます。

#### リクエスト

| HTTPメソッド | エンドポイントURL | 必須のリクエストハンドラ |
| :-----: | :-----: | :----- |
| POST | https://api.line.me/v1/oauth/accessToken | Content-Type: application/x-www-form-urlencoded |

以下の情報が、form エンコード方式でリクエストで指定されます。

| パラメータ名 | データ型 | パラメータ名<br>説明 |
| ----- | -----| ----- |
| grant_type | String | **`grant_type`**<br>認証コードで固定 |
| client_id | String | **`client_id`**<br>Channel ID |
| client_secret | String | **`client_secret`**<br>チャンネル登録時に発行された Channel Secret |
| code | String | **`code`**<br>取得した認証コード |
| redirect_uri | String | **`redirect_uri`**<br>認証コードを発行するときに提示したリダイレクト URL |

例：

```
grant_type=authorization_code&code=b5fd32eacc791df&client_id=12345&client_secret=d6524edacc8742aeedf98f&redirect_uri=https%3A%2F%2Fsample.com%2Fauth
```
```
grant_type=authorization_code
&code=b5fd32eacc791df
&client_id=12345
&client_secret=d6524edacc8742aeedf98f
&redirect_uri=https%3A%2F%2Fsample.com%2Fauth
```

#### レスポンス

アクセストークンが正常に処理されると、以下の情報が JSON 形式で返されます。

| プロパティ名 | データ型 | プロパティ名<br>説明 |
| ----- | ----- | ----- |
| mid | String | **`mid`**<br>認証済みユーザーの　ID |
| access_token | String | **`access_token`**<br>アクセストークン文字列 |
| expires_in | Integer | **`expires_in`**<br>アクセストークンの正当性で、発行されてからの経過時間を示しています |
| refresh_token | String | **`refresh_token`**<br>新しいアクセストークンにするときに必要なトークン文字列 |
| scope | ― | **`scope`**<br>`null` で固定 |

結果は以下のように出力されます。

```json
{
   "mid":"u668d5ad7e289428ef97d4ceb7841b0ad",
   "access_token":"bNl4YEFPI/hjFWhTqexp4MuEw5YPs7qhr6dJDXKwNPuLka...",
   "token_type":"Bearer",
   "expires_in":2591977,
   "refresh_token":"8iFFRdyxNVNLWYeteMMJ",
   "scope":null
 }
```

この情報はサーバーと　API　には必須です。より詳しい情報は、[REST APIs](https://developers.line.me/social-rest-api/overview)　を参照してください。

#### エラーレスポンス

エラーが発生したとき、以下のようなエラーレスポンスが返ると予想されます。

| 原因 | HTTPステータスコード | レスポンス |
| ----- | ----- | ----- |
| 生成されていないリクエストトークンが指定された<br>すでにアクセストークンに変換されたリクエストトークンが指定された | 404 | {“error”:”412″,”error_description”:”TOKEN_NOT_FOUND:b5fd32eacc791df”} |
| 期限切れのリクエストトークンが指定された | 401 | 	{“error”:”412″,”error_description”:”request token expired.”} |
| Channel ID　で指定されたチャンネルに消費者資格情報がない | 401 | {“error”:”404″,”error_description”:”CONSUMER_CREDENTIAL_NOT_FOUND”} |
| 指定されたChannel ID　の使用が中止されている | 401 403 | {“error”:”405″,”error_description”:”REVOKED or SUSPENDED”} <br> {“error”:”418″,”error_description”:”CHANNEL_INACTIVE”} |
| 指定された　Channel secret　が一致しない | 401 | {“error”:”401″,”error_description”:”channel secret is not matched. maybe abusing?”} |
| 指定された　Channel ID　のチャンネルが存在しない | 404 | {“error”:”404″,”error_description”:”12345″} |

### API を利用する

アクセストークンを取得すれば、REST API　を利用できます。より詳しい情報は、[REST APIs](https://developers.line.me/social-rest-api/overview)　をご覧ください。