概要
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にリダイレクトされます。
まず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が割り振られます。