概要
この記事はLINE Loginを使った認証の仕組みをNode.jsベースのアプリに実装するチュートリアルです。LINE側での必要な設定をおこない、WebアプリにSDKをインストールしてLINE Loginを組み込んできます。また、ログインと同時にBotをユーザーの友だちに追加するといったLINE独自の機能もカバーしていきます。
必要なスキルと環境
- Node.js/Javascriptの基本的な知識
開発の流れ
- まず最初にLoginのChannelを作成します。このChannelはユーザーから見たときに、ユーザーのLINEアカウントを利用しようとしているアプリケーションになります。
- 次にWebサービスを作成し、LINE Loginを組み込みます。
- 認証をテストします。
- 認証と同時にBotを友だちに追加する機能を追加します。
- 取得したアクセストークンを使ってAPIにアクセスします。
手順
Channelを作成する
Channelの作成については下記ドキュメントを参照ください。*なお、アプリタイプでは Webで使う を選択してください。
https://developers.line.me/ja/docs/line-login/getting-started/
作成できたらCallback URLを設定します。これはLINEの認証サーバーでの承認が終わった後にリダイレクトする先のURLになります。
今回はlocalhost上でNode.jsのWebサービスを起動させて、そこにリダイレクトするので http://localhost:5000/callback と指定します。
Webサービスを作成する
今回作成するWebサービスのソースコード一式を格納するディレクトリを作成し、そのディレクトリに移動します。
$ mkdir line-login-bootcamp
$ cd line-login-bootcamp/
npm initコマンドでpackage.jsonファイルを作成します。
$ npm init --yes
必要となるnpmパッケージをインストールします。
$ npm install --save express express-session dotenv line-login
- express: リクエストの取り扱いを容易にする汎用的なライブラリ
- express-session: セッション情報を保持するためのライブラリ。stateとnonceの値を保持します(詳しくは後述)
- dotenv: .envファイルから環境変数をロードするためのパッケージ(詳しくは後述)
- line-login: LINE Login APIのNode.js用SDK
環境変数を保存するための.envファイルを作成します。環境変数はChannel Secretのような環境ごとに異なるか、あるいは秘匿性の高い情報を保存するのに利用します。
LINE_LOGIN_CHANNEL_ID=あなたのChannel ID
LINE_LOGIN_CHANNEL_SECRET=あなたのChannel Secret
LINE_LOGIN_CALLBACK_URL=あなたのCallback URL
このWebサービスのメインスクリプトとなるindex.jsを作成します。このスクリプトではサーバーを起動、そしてSDKをインポートして任意のURLへアクセスしたときに認証フローを開始します。
"use strict";
require("dotenv").config();
// ライブラリのインポート。
const express = require("express");
const app = express();
const line_login = require("line-login");
const session = require("express-session");
const session_options = {
secret: process.env.LINE_LOGIN_CHANNEL_SECRET,
resave: false,
saveUninitialized: false
}
app.use(session(session_options));
// 認証の設定。
const login = new line_login({
channel_id: process.env.LINE_LOGIN_CHANNEL_ID,
channel_secret: process.env.LINE_LOGIN_CHANNEL_SECRET,
callback_url: process.env.LINE_LOGIN_CALLBACK_URL
});
// サーバー起動設定。
app.listen(process.env.PORT || 5000, () => {
console.log(`server is listening to ${process.env.PORT || 5000}...`);
});
// 認証フローを開始するためのルーター設定。
app.get("/auth", login.auth());
// ユーザーが承認したあとに実行する処理のためのルーター設定。
app.get("/callback", login.callback(
(req, res, next, token_response) => {
// 認証フロー成功時
res.json(token_response);
},(req, res, next, error) => {
// 認証フロー失敗時
res.status(400).json(error);
}
));
サーバーを起動
下記のコマンドを実行してサーバーを起動します。
$ node index.js
Server is listening to 5000...
認証のテスト
ブラウザを起動して http://localhost:5000/auth にアクセスしてみてください。ルーター設定で指定されているlogin.auth()によってLINEの認証サーバーへリダイレクトされることが確認できるはずです。
ログインすると承認画面が表示されます。「権限を確認」のプルダウンメニューを開くと、scopeの設定にもとづいた権限がリストされていると思います。
「同意する」をクリックするとWebサービスにリダイレクトされます。現状では「認証フロー成功時」のコードが実行され、取得したトークンの情報がJSON形式で出力されるはずです。
この部分で、実際にはトークンをデータベースに保存したり、自社サービスのアカウントを作成したりといった処理を実行することになるでしょう。
トークンには下記のような情報が含まれます。
- Social APIにアクセスするためのアクセストークン
- アクセストークンをリフレッシュするためのリフレッシュトークン
- LINE ID
- Display Name
- アイコンイメージのURL
- Email あらかじめ開発者コンソールから利用申請をおこなった上でscopeにemailを追加しておく必要があります。
ログインボタンを設置する
先ほどは認証が開始されるURL (http://localhost:5000/auth) に直接アクセスしましたが、より現実的なユースケースとしてログイン画面を作成してログインボタンを設置し、そのボタンをクリックしたら認証が開始されるように変更します。
まずログインボタンのイメージファイルを格納するディレクトリを public として作成します。
$ mkdir public
次にログインボタンの画像をダウンロードします。完全な画像セットはこちらからダウロードできますが、今回は下記のイメージだけ利用します。
先ほど作成したpublicディレクトリに、上記イメージを login_btn.png として保存します。下記のパスになっていることを確認してください。
public/login_btn.png
次にログイン画面を作成します。 index.ejs としてテンプレートファイルを下記の内容で作成します。
<html>
<body>
<a href="/auth"><img src="/login_btn.png"></img></a>
</body>
</html>
このテンプレートファイルはこのあとインストールするejsというテンプレートエンジンで出力できるファイルですが、今回の中身は純粋なHTMLです。
次にログイン画面を出力するためのテンプレートエンジンをインストールします。
$ npm install --save ejs
そして index.jsファイルを編集して、ログイン画面を出力するための設定を追加します。
// ファイルの末尾に追加
app.use(express.static(__dirname + "/public"));
app.set("view engine", "ejs");
app.get("/", (req, res) => {
res.render(__dirname + "/index");
})
これでサーバーを再起動して http://localhost:5000 にアクセスするとログインボタンが表示されるページが出力されるはずです。
このボタンをクリックすると、認証フローが開始されます。
ログインと同時にBotを友だちに追加する
現在LoginのChannelには1つのBot(厳密にはMessaging APIのChannel)を紐づけることができます。この設定をおこなうことで、ユーザーが承認画面で同意するタイミングで自社のBotをユーザーの友だちに追加することができます。Botはユーザーからメッセージに反応できる他、ユーザーに能動的にメッセージを送ることもできるため、従来Webサービスだけでは実現できなかった通知機能を実装することができます。
設定をおこなうには開発者コンソールにアクセスし、まずMessaging APIのChannelを作成する必要があります。この手順について詳しくは下記を参照ください。
LINEのBot開発 超入門(前編) ゼロから応答ができるまで - チャネルを作成する
次に該当のLoginチャネルを選択し、「このチャネルにリンクされたボット」にMessaging APIのChannelを紐付けます。
あとスクリプトを少し修正し、promptオプションを追加しその値に"consent"を設定します。
const login = new line_login({
channel_id: process.env.LINE_LOGIN_CHANNEL_ID,
channel_secret: process.env.LINE_LOGIN_CHANNEL_SECRET,
callback_url: process.env.LINE_LOGIN_CALLBACK_URL,
prompt: "consent" // 追加
});
このオプションは、ユーザーが権限について一度承認していても、再度承認画面を表示するために設定します。これでサーバーを再起動し、ブラウザで再度 http://localhost:5000 にアクセスしてみてください。ログインの後に承認画面が表示され、友だち追加のチェックボックスが表示されるはずです。
ここでユーザーが友だち追加にチェックして同意するとBotが友だちに追加されます。ただ、デフォルトではチェックははずれた状態になっており、ユーザーがこのチェックボックスに気づかず先に進んでしまう可能性があります。
この友だち追加をより明確にユーザーに求めるのであれば、さらにスクリプトを修正してbot_promptオプションを追加してその値に"aggressive"と設定します。
const login = new line_login({
channel_id: process.env.LINE_LOGIN_CHANNEL_ID,
channel_secret: process.env.LINE_LOGIN_CHANNEL_SECRET,
callback_url: process.env.LINE_LOGIN_CALLBACK_URL,
prompt: "consent",
bot_prompt: "aggressive" // 追加
});
これでもう一度サーバーを再起動してブラウザで承認画面に向かうと、同意した後に友だち追加を求めるためのスクリーンが表示されます。
ここでユーザーが友だち追加ボタンをクリックしてくれれば、Botが友だちに追加された上でWebサービスにリダイレクトされるはずです。
トークンを使ったAPIへのアクセス
最後にアクセストークンを使ってAPIへのアクセスを試してみます。私たちはLogin ChannelにBotを紐付けましたが、たとえユーザーがログインの際には友だち追加してくれたとしても、その後ブロックされる可能性もあります。そこで、とあるタイミングで任意のユーザーとBotが友だちになっているかどうか確認するAPIを利用します。
今回は認証後にそのままアクセストークンを使って友だち状況を確認するという流れでコードを修正します。
app.use("/callback", login.callback(
(req, res, next, token_response) => {
// 認証フロー成功時
login.get_friendship_status(token_response.access_token).then((response) => {
res.json(response);
})
},
(req, res, next, error) => {
// 認証フロー失敗時
res.status(400).json(error);
}
));
認証が成功した後、login.get_friendship_status(アクセストークン)を実行して友だち状況を確認しています。成功すれば下記のJSONレスポンスがブラウザに結果が表示されるはずです。
{"friendFlag": true} //友だちになっていなければfalse
さらに学ぶには
ログインのAPIに関する網羅的なドキュメントは下記の公式サイトにあります。
また、今回はline-loginといったミニマムなSDKを利用しましたが、LINE LoginはOpenID Connectの標準仕様に従っているため、OpenID Connectに対応する passport.js などの汎用的なライブラリもすべからく利用できます。そのあたりも是非試してみてください。