LoginSignup
14
5

More than 3 years have passed since last update.

LINEログインを、Node.js + Herokuでやってみた

Posted at

お仕事でLINEログインをチームで実装する機会があったので、自分でもできるように小さなサービスを作ってみようと思います。

まずは、LINEログインボタンを表示し、それを押すとLINEログインの実行を行い、ログインしたアカウント情報を表示するところまで実装します。

サーバサイドはNode.jsを利用し、インフラとしてはHerokuを利用します。
(LINEからのcallback URLを指定する必要があるので、Herokuが便利です。)

事前準備

Node: v12.13.1
Heroku CLI: 7.35.0

Nodeアプリ環境の構築

https://github.com/noboru-i/line-note/commit/d0d935c6075b5f3f007b306d7aeaf14b2134355e
https://github.com/noboru-i/line-note/commit/94518c502c16b300e63bc8d4bdf73eb95d9b3d9d

まずは、サンプルを持ってきて、フォルダ名などをリネーム。

git clone https://github.com/heroku/node-js-getting-started.git
mv node-js-getting-started line-note
cd line-note
npm install

その後、READMEやpackage.jsonのアプリ名部分などを整理。

Heroku環境の作成・仮デプロイ

heroku create line-note
git push heroku master
heroku open

これで、とりあえずサンプルのNode.jsアプリが動作していることを確認できた。

LINE Developersにて、LINEログインチャンネルを作成

https://developers.line.biz/console/ より、個人のLINEアカウントでログイン。

適当な名前を入れてProviderを作成。

いろいろ適当に入力し、LINEログインチャンネルを作成。

"LINE Login"タブの"Callback URL"に、 https://line-note.herokuapp.com/callback を指定。

Herokuアプリの環境変数として、チャンネルID / チャンネルシークレットを保存しておく。

heroku config:set LINECORP_PLATFORM_CHANNEL_CHANNELID=(コンソールで確認できる"Channel ID")
heroku config:set LINECORP_PLATFORM_CHANNEL_CHANNELSECRET=(コンソールで確認できる"Channel secret")

ローカルでの確認用に、 .env にも同様に設定しておく。
(とはいえ、callbackが本番ドメインの方に来るので、ローカル環境は使いませんでした。)

LINECORP_PLATFORM_CHANNEL_CHANNELID=(コンソールで確認できる"Channel ID")
LINECORP_PLATFORM_CHANNEL_CHANNELSECRET=(コンソールで確認できる"Channel secret")

コードの修正し、LINEログインを実装

とりあえずログインボタンを作れればいいので、 views/pages/index.ejs を開いて、上の方にあるボタンを以下のように書き換える。

<a type="button" class="btn btn-lg btn-default" href="/login">LINEログイン</a>

次に、 /login にアクセスされたときに、LINEログインのページにリダイレクトする仕組みを作っておく。
同様に、 /callback にアクセスが来たとき、リクエストパラメータの code を出力することにしておく。
index.js を、以下のように変更。

const express = require('express')
const path = require('path')
const PORT = process.env.PORT || 5000

const querystring = require('querystring');

express()
  .use(express.static(path.join(__dirname, 'public')))
  .disable('etag')
  .set('views', path.join(__dirname, 'views'))
  .set('view engine', 'ejs')
  .get('/', (req, res) => res.render('pages/index'))
  .get('/login', (req, res) => {
    const query = querystring.stringify({
      response_type: 'code',
      client_id: process.env.LINECORP_PLATFORM_CHANNEL_CHANNELID,
      redirect_uri: 'https://line-note.herokuapp.com/callback',
      state: 'hoge', // TODO: must generate random string
      scope: 'profile',
    })
    res.redirect(301, 'https://access.line.me/oauth2/v2.1/authorize?' + query)
  })
  .get('/callback', (req, res) => {
    res.send('code: ' + req.query.code)
  })
  .listen(PORT, () => console.log(`Listening on ${ PORT }`))

これを git push heroku master にてデプロイすると、ログインのフローが確認できる。
まだ、codeが見えるだけ。

LINEの情報を取得する

https://github.com/noboru-i/line-note/commit/85ba05cae417ea5b004ff60fac1dc159c97f13b6
https://github.com/noboru-i/line-note/commit/d6e3f23e4a533147132c4ee613e57de746085d39

codeからaccess tokenを取得、それを利用してユーザ情報を取得する。

まずは、サーバからAPIを実行するために、requestモジュールを導入。

npm install request --save

そして、以下のように実装する。

const request = require('request')

express()
  // ...
  .get('/callback', (req, res) => {
    request
      .post({
        url: `https://api.line.me/oauth2/v2.1/token`,
        form: {
          grant_type: "authorization_code",
          code: req.query.code,
          redirect_uri: 'https://line-note.herokuapp.com/callback',
          client_id: process.env.LINECORP_PLATFORM_CHANNEL_CHANNELID,
          client_secret: process.env.LINECORP_PLATFORM_CHANNEL_CHANNELSECRET,
        }
      }, (error, response, body) => {
        if (response.statusCode != 200) {
          res.send(error)
          return
        }
        request
          .get({
            url: 'https://api.line.me/v2/profile',
            headers: {
              'Authorization': 'Bearer ' + JSON.parse(body).access_token
            }
          }, (error, response, body) => {
            if (response.statusCode != 200) {
              res.send(error)
              return
            }
            res.send(body)
          })
      })
  })
  .listen(PORT, () => console.log(`Listening on ${ PORT }`))

これによって、以下のようなレスポンスが画面に表示される。

{
    userId: "XXX",
    displayName: "XXX",
    pictureUrl: "https://profile.line-scdn.net/ch/v2/p/XXX"
}

今回やらなかったこと

access_token / refresh_token

access_token は30日で有効期限切れとなります。
access_token が失効したあと、10日以内に refresh_token を利用すると、再度 access_tokenrefresh_token を取得できます。

stateのチェック

CSRF対策のため、 /authorize にアクセスする際のstateパラメータにランダムな文字列を生成して、 /callback で返却されたstateとチェックする必要があります。
セッションなどに一時的に保存して、チェックする必要があります。

参考

https://developers.line.biz/ja/docs/line-login/web/try-line-login/
line-login-starterというサンプルアプリの使い方が書いてある。

https://github.com/nkjm/line-login
LINEログインのunofficial SDK。今回は参考として。

14
5
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
14
5