LoginSignup
7
3

More than 1 year has passed since last update.

LINEログイン v2.1を使ったログイン(PKCEも対応)

Last updated at Posted at 2021-07-13

概要

LINEログイン v2.1を使ったログインとメッセージ送信のPHPサンプルコードです。

コード

こちらに公開しています。
https://github.com/takezi/line-login

コードの要点を解説

LINEのログインはOAuth 2.0/OpenID Connectに基づいた実装となっています。

ユーザーに認証と認可を要求する

ドキュメントはこちらです。
https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request

session_start();
$_SESSION['oauth_state'] = bin2hex(random_bytes(16));
$_SESSION['oauth_nonce'] = bin2hex(random_bytes(16));
$_SESSION['oauth_code_verifier'] = base64url_encode(random_bytes(32));

$url = LINE_LOGIN_AUTHORIZE_URL . '?' . http_build_query([
    'response_type' => 'code',
    'client_id' => LINE_LOGIN_CHANNEL_ID,
    'redirect_uri' => LINE_LOGIN_CALLBACK_URL,
    'state' => $_SESSION['oauth_state'],
    'scope' => LINE_LOGIN_SCOPE,
    'nonce' => $_SESSION['oauth_nonce'],
    'code_challenge' => base64url_encode(hash('sha256', $_SESSION['oauth_code_verifier'], true)),
    'code_challenge_method' => 'S256'
]);

// 認可URLにリダイレクト
header("Location: $url");

セキュリティ対策として、state,nonce,code verifier(PKCE)を使っています。
全ては必要ないかも知れませんが、目的が異なり、さほど手間でも無いため、全て入れておいて良いでしょう。

stateとnonceはrandom_bytesで生成しています。GUIDと同じ16バイトあれば十分でしょう。
code verifierはRFC 7636に、使える文字と最低文字文字数が43文字と定められています。
RFCに、32バイトのランダムバイトをBase64URLエンコードすれば43文字が生成できるとあります。

Base64URLエンコードとはBase64の一部の文字を、URLエンコードされない文字に置換して、末尾のパディングを除去したものです。
次のような関数を作って変換することができます。

// Base64URLエンコードするための関数
function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

コールバックURLで認可コードを受け取る

認可が完了すると、ユーザー画面はコールバックURLにリダイレクトされます。

ドキュメントはこちらです。
https://developers.line.biz/ja/docs/line-login/integrate-line-login/#receiving-the-authorization-code-or-error-response-with-a-web-app

まずstateの検証を行います。

session_start();

// stateの検証
if($_SESSION['oauth_state'] != $_GET['state']) {
    echo '認可サーバーが無効なstateパラメータを返却しました。';
    exit;
}

次にエラーレスポンスかどうかチェックします。この辺りは RFC 6749 に従っています。

// エラーチェック
if(isset($_GET['error'])) {
    echo '<p>許可サーバーがエラーを返しました:' . htmlspecialchars($_GET['error'], ENT_QUOTES, 'UTF-8') . '</p>';
    echo '<p>' . htmlspecialchars($_GET['error_description'], ENT_QUOTES, 'UTF-8') . '</p>';
    exit;
}

アクセストークンを発行する

受け取った認可コードを使って、アクセストークンを発行します。

ドキュメントはこちらです。
https://developers.line.biz/ja/reference/line-login/#issue-access-token

$body = [
    'grant_type' => 'authorization_code',
    'code' => $_GET['code'],
    'redirect_uri' => LINE_LOGIN_CALLBACK_URL,
    'client_id' => LINE_LOGIN_CHANNEL_ID,
    'client_secret' => LINE_LOGIN_CHANNEL_SECRET,
    'code_verifier' => $_SESSION['oauth_code_verifier']
];
$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => 'Content-Type: application/x-www-form-urlencoded',
        'content' => http_build_query($body, '', '&')
    ]
]);
$res = json_decode(file_get_contents(LINE_LOGIN_TOKEN_URL, false, $context), true);

素のPHPでPOSTしているので多少冗長です。何かしらのライブラリを利用する場合は書き換えてください。

code verifierの検証は、このタイミングでLINEのサーバー側で行われます。
レスポンスにはアクセストークンに加えて、IDトークンも含まれます(scopeでopenidを指定した場合)。

IDトークンを検証する

通常IDトークンは自力で検証しますが、LINEは検証用のAPIを用意してくれています。
https://developers.line.biz/ja/reference/line-login/#verify-id-token

nonceの検証も、このAPIで実施できます。

$body = [
    'id_token' => $res['id_token'],
    'client_id' => LINE_LOGIN_CHANNEL_ID,
    'nonce' => $_SESSION['oauth_nonce']
];
unset($_SESSION['oauth_nonce']);
$context = stream_context_create([
    'http' => [
        'method' => 'POST',
        'header' => 'Content-Type: application/x-www-form-urlencoded',
        'content' => http_build_query($body, '', '&'),
        'ignore_errors' => true
    ]
]);
$res = json_decode(file_get_contents(LINE_LOGIN_VERIFY_URL, false, $context), true);
if (isset($res['error'])) {
    echo 'IDトークンの検証に失敗しました:' . htmlspecialchars($res['error_description'], ENT_QUOTES, 'UTF-8');
    exit;
}

ログインセッションを設定

最後に取得できたLINEのユーザーIDと名前をセッションに保存します。

session_regenerate_id(true);
$_SESSION = [];
$_SESSION['user_id'] = $res['sub'];
$_SESSION['name'] = $res['name'];

ユーザーIDを使ってLINE公式アカウントで、特定のユーザーだけにメッセージを送ることも可能です。
メッセージ送信のサンプルは github に置いてある send.php を参考にしてください。

ユーザーIDは、LINE Developersコンソールで最初に作成したプロバイダの単位でユニークです。
プロバイダが異なると同じLINEユーザーでも異なるIDが割り振られます。

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3