LINEログインとID連携:会員情報と友だちを結びつける

公開 書いた人 大林 諒

会員サイトで管理している「会員番号123の山田さん」と、LINE公式アカウントの友だちの1人を同じ人だと分かるようにするのが、この記事でいうID連携です。結びつけておくと、レッスンの前日に予約した本人だけへLINEで案内を送れます。公式アカウントの標準機能だけではできず、LINE Developersで作るチャネルと、受け口になる小さなサーバーが要ります。この記事では、結びつける方法を4つ比べたうえで、LINEログインのボタンを会員サイトに付ける流れと、トークから連携するアカウント連携の流れを、どちらも公式の手順どおりに書きます。例は全記事で共通の、予約制の小さな料理教室「サンプル料理教室」です。前提として、公式アカウントでMessaging APIを使える状態にしてある(「Messaging APIの始め方:チャネル・アクセストークン・Webhook」の内容)ものとします。

この記事の内容
  1. 先に決めること
  2. 結びつける4つの方法
  3. LINEログインのチャネルを作る
  4. 会員サイトにログインボタンを付ける
  5. ログインと同時に友だち追加してもらう
  6. トークから会員番号と結ぶ(アカウント連携)
  7. サンプル料理教室の例:前日に本人へ送る
  8. 個人情報と同意の取り方
  9. 応用
  10. できないことと、その代わり
  11. よく詰まるところ
  12. 次にやること

先に決めること

ここを飛ばすと、作ったあとに作り直しになります。

1つ目は、プロバイダーを1つに揃えることです。LINE Developersでは、チャネルをプロバイダーと呼ぶ入れ物の下に作ります。ユーザーIDはプロバイダーごとに別の値が発行され、同じプロバイダーの下ならLINEログインのチャネルとMessaging APIのチャネルで同じIDになります。プロバイダーが違うと、同じ人でもIDが変わり、ログインで取ったIDに公式アカウントからメッセージを送れません。しかも、公式アカウントでMessaging APIを有効にするときに選んだプロバイダーは、あとから変えられません。チャネルを別のプロバイダーへ移すこともできません。運用代行や拡張ツールの会社が持っているプロバイダーの下に作ると、契約を切ったときに困ります。自社名のプロバイダーを1つ作り、そこに全部置きます。

2つ目は、どこから連携を始めるかです。会員サイトのマイページから「LINEで連携」を押してもらうならLINEログイン、LINEのトーク画面のリッチメニューから始めるならMessaging APIのアカウント連携が素直です。サンプル料理教室は、会員サイトに毎回ログインする人が少なく、LINEのほうがよく開かれるので、リッチメニューからの連携を主にし、会員サイトにもLINEログインのボタンを付けます。

3つ目は、何を取るかです。結びつけに要るのはユーザーIDだけです。表示名やプロフィール画像は変わるので、会員の名前は会員台帳のものを使います。メールアドレスは、取るなら事前に申請が要ります。サンプル料理教室は会員台帳にメールアドレスがあるので取りません。

4つ目は、作る人と置き場所です。どの方法でも、LINEからの戻り先を受けるサーバーが要ります。会員サイトがWordPressなら同じサーバーに置けますし、別の小さなサーバーやn8nで受けることもできます。チャネルシークレットやチャネルアクセストークンを置く場所なので、ブラウザ側のJavaScriptだけでは作れません。

結びつける4つの方法

検索すると「LINE ID連携」「アカウント連携」「LINEログイン」が同じ意味で出てきますが、仕組みは別物です。

方法どこから始まるか必要なもの結びつくもの向く場面
LINEログイン会員サイト・アプリのログインボタンLINEログインのチャネル、コールバックを受けるサーバー会員とユーザーID。友だちかどうかは別Webの会員サイトがあり、会員登録やログインをLINEで済ませたい
友だち追加オプションLINEログインの同意画面LINEログインのチャネルと、同じプロバイダーのMessaging APIチャネルログインと同時に公式アカウントの友だちになるログインした会員に、そのままLINEで送りたい
Messaging APIのアカウント連携公式アカウントのトーク画面Messaging APIのチャネル、Webhookを受けるサーバー、会員サイトのログイン画面友だちと会員番号すでに友だちの人を、あとから会員と結びたい
LIFFLINEの中で開くWebページLINEログインのチャネルに追加したLIFFアプリ開いた人のユーザーID。友だち追加オプションも付けられるLINEの中で予約や会員登録のフォームを開きたい

迷ったら、すでに友だちが多い公式アカウントはアカウント連携から、Webの会員サイトが中心ならLINEログインと友だち追加オプションから始めます。両方を同じプロバイダーで作っておけば、どちらで結んでも同じユーザーIDになります。

もう1つ、言葉の取り違えを先に片づけておきます。

呼び方中身連携に使うか
ユーザーIDU で始まり16進数32桁が続く文字列。LINEプラットフォームが発行し、プロバイダーごとに違う使う。会員番号と結びつけるのはこれ
LINE ID友だち検索に使う、利用者が自分で決めるID使わない。連携トークンの発行にも使えない
表示名利用者がいつでも変えられる名前使わない。名寄せの手がかりにもしない
公式アカウントのベーシックID・プレミアムID公式アカウント側のID。トークメニューのアカウント名の下とビジネスプロフィールに出る使わない。人を見分ける値ではない

LINEログインのチャネルを作る

LINEログインそのものは無料で使えます(2026年10月時点)。手順はPCのブラウザで行います。

  1. LINE Developersコンソールに、公式アカウントの管理者と同じアカウントでログインする。
  2. 公式アカウントでMessaging APIを有効にしたときに選んだプロバイダーをクリックする。
  3. 「チャネル設定」タブで「LINEログイン」を選ぶ。
  4. 「サービスを提供する地域」で日本を選ぶ。
  5. 「会社・事業者の所在国・地域」で日本を選ぶ。
  6. 「チャネル名」に サンプル料理教室 会員サイト と入れる。「LINE」やそれに似た文字は入れられません。
  7. 「チャネル説明」と「メールアドレス」を入れる。
  8. 「アプリタイプ」で「ウェブアプリ」を選ぶ(もう1つは「ネイティブアプリ」)。「2要素認証の必須化」は初期値のオンのままにします。
  9. 「プライバシーポリシーURL」に会員サイトのプライバシーポリシーのURLを入れる。認証プロバイダーでなければ任意ですが、入れておきます。
  10. LINE開発者契約を確認して「LINE開発者契約に同意します。」にチェックを入れ、「作成」を押す。
LINE Developersコンソールで、LINEログインのチャネルを新規作成する入力画面
LINE Developersコンソールで、LINEログインのチャネルを新規作成する入力画面

作ったチャネルは「開発中」の状態です。この状態ではチャネルのAdminかTesterの権限を持つ人しかログインできません。スタッフで動きを確かめたら、ステータスを「公開済み」に変えます。「公開済み」から「開発中」には戻せません。

続けて、戻り先のURLを登録します。

  1. 作ったチャネルの「LINEログイン設定」タブを開く。
  2. 「コールバックURL」の「編集」を押し、https://member.example.com/line/callback を入れて「更新」を押す。テスト用のURLもあるなら、改行して並べる。
  3. 同じタブの「ウェブアプリでLINEログインを利用する」がオンになっているか確かめる。
「LINEログイン設定」タブでコールバックURLを入れたところ
「LINEログイン設定」タブでコールバックURLを入れたところ

メールアドレスも取るなら、「チャネル基本設定」タブの「OpenID Connect」で「申請」を押し、申請条件に同意して、メールアドレスの取得と使い方を利用者に示す文面のスクリーンショットを上げます。受理されると「メールアドレス取得権限」に「申請済み」と出ます。会員登録画面の「LINEで登録すると、LINEに登録したメールアドレスを会員サイトの連絡先として使います」のような文を先に作っておく必要があります。

会員サイトにログインボタンを付ける

LINEログインの中身は、OAuth 2.0の認可コードの流れとOpenID Connectです。会員サイトから見ると、次の4往復になります。

順番会員サイトがすることLINE側から返るもの
1ボタンを押した人を認可URLへ送る。state と nonce を作ってセッションに残すLINEのログイン・同意画面
2コールバックURLで受ける。state が送ったものと同じか確かめるcode(認可コード)と state
3認可コードをトークンのエンドポイントへ送るaccess_token、id_token、refresh_token
4IDトークンを検証し、中の sub(ユーザーID)を会員番号と結ぶ表示名・画像・ユーザーIDの入ったペイロード

認可URLは次の形です。redirect_uri はURLエンコードし、state はログインのたびにランダムに作ります。state 自体はURLエンコードが要らない英数字にします。

https://access.line.me/oauth2/v2.1/authorize?response_type=code&client_id=YOUR_LOGIN_CHANNEL_ID&redirect_uri=https%3A%2F%2Fmember.example.com%2Fline%2Fcallback&state=8f3a1c0d9e7b42a6&scope=profile%20openid&nonce=5b2e9d71c4a8f036&bot_prompt=normal

scope は profile と openid を付けます。openid を付けないとIDトークンが返りません。email を付けるのは申請が通ってからです。

認可コードは有効期間10分で、1回しか使えません。受け取ったらすぐにトークンと交換します。

curl -X POST https://api.line.me/oauth2/v2.1/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=RECEIVED_CODE' \
  --data-urlencode 'redirect_uri=https://member.example.com/line/callback' \
  -d 'client_id=YOUR_LOGIN_CHANNEL_ID' \
  -d 'client_secret=YOUR_LOGIN_CHANNEL_SECRET'

返ってくるアクセストークンの有効期間は30日、リフレッシュトークンは発行から最長90日です。結びつけが目的なら、アクセストークンを長く持ち続ける必要はありません。IDトークンは、署名を自分で検証するか、検証のエンドポイントに投げます。小さな会員サイトなら後者が楽です。

curl -X POST https://api.line.me/oauth2/v2.1/verify \
  -d 'id_token=RECEIVED_ID_TOKEN' \
  -d 'client_id=YOUR_LOGIN_CHANNEL_ID' \
  -d 'nonce=NONCE_SAVED_IN_SESSION'

成功すると、sub にユーザーID、name に表示名、picture に画像のURL、amr にログインの方法(pwd、lineautologin、lineqr、linesso、mfa のどれか)が入って返ります。amr は条件によっては入らないことがあるので、これに頼った処理は作りません。IDトークンを使わずに GET https://api.line.me/v2/profile にアクセストークンを付けて、userId と displayName を取ることもできます。

ここまでをNode.js(18以上)で書くと次のとおりです。会員サイトへのログインは既存の仕組みのままとし、ログイン済みの会員が /line/login を開く前提です。npm install express express-session で動きます。

// server.mjs
import express from 'express';
import session from 'express-session';
import crypto from 'node:crypto';
import { appendFile } from 'node:fs/promises';

const CHANNEL_ID = process.env.LINE_LOGIN_CHANNEL_ID;
const CHANNEL_SECRET = process.env.LINE_LOGIN_CHANNEL_SECRET;
const CALLBACK_URL = 'https://member.example.com/line/callback';

const app = express();
app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false }));

app.get('/line/login', (req, res) => {
  if (!req.session.memberNo) return res.redirect('/login');
  const state = crypto.randomBytes(16).toString('hex');
  const nonce = crypto.randomBytes(16).toString('hex');
  req.session.lineState = state;
  req.session.lineNonce = nonce;
  const q = [
    'response_type=code',
    'client_id=' + CHANNEL_ID,
    'redirect_uri=' + encodeURIComponent(CALLBACK_URL),
    'state=' + state,
    'scope=' + encodeURIComponent('profile openid'),
    'nonce=' + nonce,
    'bot_prompt=normal',
  ].join('&');
  res.redirect('https://access.line.me/oauth2/v2.1/authorize?' + q);
});

app.get('/line/callback', async (req, res) => {
  const { code, state, error } = req.query;
  if (error) return res.redirect('/mypage?line=canceled');
  if (!state || state !== req.session.lineState) return res.status(400).send('state mismatch');
  delete req.session.lineState;

  const tokenRes = await fetch('https://api.line.me/oauth2/v2.1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code', code, redirect_uri: CALLBACK_URL,
      client_id: CHANNEL_ID, client_secret: CHANNEL_SECRET,
    }),
  });
  if (!tokenRes.ok) return res.status(502).send('token error');
  const token = await tokenRes.json();

  const verifyRes = await fetch('https://api.line.me/oauth2/v2.1/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({ id_token: token.id_token, client_id: CHANNEL_ID, nonce: req.session.lineNonce }),
  });
  if (!verifyRes.ok) return res.status(401).send('id_token invalid');
  const payload = await verifyRes.json();

  // 会員番号, ユーザーID, 連携した日時, 経路 を1行で残す(本番は会員台帳のDBへ)
  await appendFile('links.csv', [req.session.memberNo, payload.sub, new Date().toISOString(), 'line_login'].join(',') + '\n');
  res.redirect('/mypage?line=linked');
});

app.listen(3000);

ログインボタンは、LINEの「LINEログインボタン デザインガイドライン」に従います。テンプレートをダウンロードした時点でガイドラインに同意した扱いになり、基本色は #06C755 から変えられません。自分で緑のボタンを描かず、配布されている画像を使います。

会員サイトのマイページに置いた「LINEで連携」ボタン
会員サイトのマイページに置いた「LINEで連携」ボタン

ログインの方法は環境で変わります。スマートフォン版LINEにログインしている状態で、LINE内ブラウザかスマートフォンの外部ブラウザから認可URLを開くと、自動ログインになり画面は出ません。PC版LINEでは自動ログインは動きません。ブラウザに前回のログインが残っていれば、先に「次のアカウントでログイン」の確認画面が出て、「ログイン」か「別のアカウントでログイン」を選びます。別のアカウントを選ぶと、メールアドレスとパスワードの入力欄と「ログイン」、それに「QRコードログイン」が出ます。プライベートブラウズや、OSの仕様で自動ログインが失敗することもあります。

PCのブラウザで出るLINEログイン画面(メールアドレスとQRコードの切り替え)
PCのブラウザで出るLINEログイン画面(メールアドレスとQRコードの切り替え)

ログインと同時に友だち追加してもらう

友だち追加オプションは、LINEログインの同意画面に「公式アカウントを友だち追加する」の選択を出す仕組みです。条件は2つあります。公式アカウントのMessaging APIチャネルが、LINEログインのチャネルと同じプロバイダーにあること。操作する人が、LINEログインのチャネルのAdmin権限と、公式アカウントの管理者権限の両方を持っていることです。

  1. LINE Developersコンソールで、LINEログインのチャネルがあるプロバイダーを開く。
  2. LINEログインのチャネルをクリックする。
  3. 「チャネル基本設定」タブの「リンクされたLINE公式アカウント」で「編集」を押す。
  4. サンプル料理教室の公式アカウントを選び、「更新」を押す。
  5. 認可URLに bot_prompt=normal か bot_prompt=aggressive を付ける。

1つのLINEログインのチャネルにリンクできる公式アカウントは1つです。normal は同意画面の中に選択を出し、aggressive は同意画面のあとに友だち追加するかを聞く画面を別に出します。サンプル料理教室は normal にしています。体験レッスンの予約をLINEログイン経由にしたとき、aggressive だと画面が1枚増えて、ログインそのものをやめる人が出たからです。

同意画面の出方は、その人と公式アカウントの関係で変わります。

同意画面を開いたときの関係出るもの
まだ友だちではない友だち追加のオプション。有効にして進むと友だちになる
ブロックしているブロック解除のオプション
すでに友だち友だち追加済みであることの表示。オプションは出ない
認証プロバイダー配下のチャネルで bot_prompt=normalオプションが最初から有効になっている
LINEログインの同意画面に友だち追加のオプションが出ているところ
LINEログインの同意画面に友だち追加のオプションが出ているところ

ログインのあと、コールバックURLに friendship_status_changed が付きます。true ならこのログインで友だち追加かブロック解除が起き、false なら変化なしです。オプションが出なかったときはこのパラメータ自体が付きません。今この瞬間に友だちかどうかは、アクセストークンで GET https://api.line.me/friendship/v1/status を呼ぶと friendFlag で返ります。true は友だちでブロックしていない状態、false はそれ以外です。前日の案内を送る対象を決めるときは、連携の有無だけでなくここも見ておくと、届かない相手に送ろうとしなくて済みます。

トークから会員番号と結ぶ(アカウント連携)

Messaging APIのアカウント連携は、LINEログインのチャネルがなくても使えます。そのかわり、相手が公式アカウントの友だちであることが前提です。公式の流れは5段階です。

  1. 友だちのユーザーIDで、連携トークンを発行する。
  2. 連携トークンを付けた連携URLを、その人に送る。
  3. その人が連携URLを開き、会員サイトにログインする。会員サイトは会員番号を得る。
  4. 会員サイトが nonce を作って会員番号と一緒に保存し、その人をLINEの連携エンドポイントへ送る。
  5. LINEからアカウント連携イベントが届いたら、nonce で会員番号を引き、ユーザーIDと結ぶ。

連携トークンは、Messaging APIのチャネルアクセストークンで発行します。有効期間は10分で、1回しか使えません。

curl -X POST https://api.line.me/v2/bot/user/U0123456789abcdef0123456789abcdef/linkToken \
  -H 'Authorization: Bearer YOUR_CHANNEL_ACCESS_TOKEN'
{ "linkToken": "NMZTNuVrPTqlr2IF8Bnymkb7rXfYv5EY" }

サンプル料理教室では、リッチメニューの「会員連携」をタップするとトークに 会員連携 と送られるようにし、Webhookでそれを受けたら連携トークンを発行して、ボタン付きのテンプレートメッセージで返しています。公式の例はプッシュメッセージですが、ユーザーの発言への応答メッセージで返せばメッセージ通数に数えられません。

{
  "replyToken": "RECEIVED_REPLY_TOKEN",
  "messages": [{
    "type": "template",
    "altText": "会員サイトとLINEを連携します",
    "template": {
      "type": "buttons",
      "text": "会員サイトにログインすると、レッスン前日のご案内がLINEに届きます。",
      "actions": [{
        "type": "uri",
        "label": "連携する",
        "uri": "https://member.example.com/line/link?linkToken=NMZTNuVrPTqlr2IF8Bnymkb7rXfYv5EY"
      }]
    }
  }]
}

これを POST https://api.line.me/v2/bot/message/reply に送ります。

トーク画面に届いた「連携する」ボタン付きのメッセージ
トーク画面に届いた「連携する」ボタン付きのメッセージ

/line/link では、まだ会員サイトにログインしていなければログイン画面を出し、ログイン後に linkToken を持ったまま戻します。ログインできたら nonce を作ります。nonce は推測できず1回だけ使う値で、長さは10文字以上255文字以下です。会員番号のような予測できる値は使いません。公式の推奨は、安全な乱数で16バイト以上を作り、Base64にすることです。

// server.mjs に追記。/line/link で会員ログインを確かめたあとの処理
const nonceStore = new Map();
const nonce = crypto.randomBytes(16).toString('base64');
// nonce と会員番号を結んで保存(10分ほどで捨てる)
nonceStore.set(nonce, { memberNo: req.session.memberNo, createdAt: Date.now() });
res.redirect('https://access.line.me/dialog/bot/accountLink?linkToken='
  + encodeURIComponent(req.query.linkToken) + '&nonce=' + encodeURIComponent(nonce));

Base64には + や / や = が入るので、URLに載せるときにエンコードを忘れないようにします。

LINEは、連携トークンを発行された本人が開いたかを確かめ、Webhookにアカウント連携イベントを送ってきます。

状況Webhookに届くものすること
本人と確認できたtype が accountLink、link.result が ok、link.nonce、source.userIdnonce で会員番号を引き、ユーザーIDと保存する。応答で「連携しました」と返す
本人と確認できなかったlink.result が failed。source と replyToken は入らない何も結ばない。保存した nonce は捨てる
連携トークンが期限切れ・使用済み何も届かない。その人の画面にエラーが出るトークからもう一度「会員連携」を押してもらう

Webhookは、署名を確かめてから処理します。チャネルシークレットを鍵にリクエストボディをHMAC-SHA256で計算し、Base64にしたものが x-line-signature ヘッダーと一致するかを見ます。ボディをパースしてから計算すると一致しません。

// server.mjs に追記。Webhook URL は https://member.example.com/webhook
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = crypto.createHmac('sha256', process.env.MESSAGING_CHANNEL_SECRET).update(req.body).digest('base64');
  if (sig !== req.get('x-line-signature')) return res.sendStatus(401);
  res.sendStatus(200);
  const { events } = JSON.parse(req.body.toString('utf8'));
  for (const ev of events) {
    if (ev.type !== 'accountLink') continue;
    const saved = nonceStore.get(ev.link.nonce);
    nonceStore.delete(ev.link.nonce);
    if (ev.link.result !== 'ok' || !saved) continue;
    await appendFile('links.csv', [saved.memberNo, ev.source.userId, new Date().toISOString(), 'account_link'].join(',') + '\n');
  }
});

自前で「会員番号を入力してください」とトークで聞いてIDを結ぶ作り方は避けます。他人の会員番号を入れれば、その人の会員情報に自分のLINEが結ばれてしまうからです。公式の手順は、連携URLを発行された本人が開いたかをLINE側で確かめるので、このすり替えを防げます。

サンプル料理教室の例:前日に本人へ送る

サンプル料理教室では、会員台帳(Googleスプレッドシートか、顧客管理のkintone)に次の列を足しています。

列例使い道
会員番号M-0123会員サイトのID。結びつけの片側
LINEユーザーIDU0123456789abcdef0123456789abcdef送り先。結びつけのもう片側
連携の経路line_login / account_linkどちらで結んだか
連携した日時2026-10-20 19:42同意した時点の記録
同意した文面の版2026-10版どの説明を読んで同意したか
連携の状態連携中 / 解除解除したら送らない

予約は会員番号で入っているので、毎晩18時に翌日のレッスンを予約している会員を引き、連携中でLINEユーザーIDがある人にだけプッシュメッセージを送ります。

curl -X POST https://api.line.me/v2/bot/message/push \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_CHANNEL_ACCESS_TOKEN' \
  -d '{
    "to": "U0123456789abcdef0123456789abcdef",
    "messages": [{
      "type": "text",
      "text": "山田さま、明日10月28日(水)19:00から「秋の和定食」のレッスンです。エプロンをお持ちください。変更はこのトークでご連絡ください。"
    }]
  }'

名前は会員台帳の名前を入れます。LINEの表示名はニックネームのことが多く、宛名に使うと違和感が出ます。プッシュメッセージはメッセージ通数に数えられます。2026年10月時点で、コミュニケーションプランは月200通、ライトプランは月5,000円で5,000通、スタンダードプランは月15,000円で30,000通まで無料で送れます。スタンダードプランだけは、30,000通を超えた分も追加メッセージ(1通あたり約3円まで、送る数で単価が変わる。税別)として送れます。コミュニケーションプランとライトプランは追加メッセージを送れません。ブロックしている人のユーザーIDに送った分は数えられません。前日・当日の送り分けや、無断キャンセルへの効き方は「予約のリマインドをLINEで自動送信する:前日・当日の通知と無断キャンセル対策」に書いています。

会員台帳のスプレッドシートに、LINEユーザーIDと連携の状態の列を足したところ
会員台帳のスプレッドシートに、LINEユーザーIDと連携の状態の列を足したところ

連携していない会員には、これまでどおりメールで送ります。全員をLINEに寄せようとせず、連携した人だけLINEに切り替える形にすると、連携率が低いうちから運用を始められます。

個人情報と同意の取り方

ユーザーIDは、会員台帳と結んだ時点でその人を特定できる情報になります。LINE開発者契約でも、ログイン情報がアプリで使えるようになることを利用者に知らせること、同意を得た時期以降に同意を得た用途でだけ使うこと、取った情報で第三者のサービスに広告を出さないことが決められています。

サンプル料理教室では、連携ボタンのすぐ上に次の文を置いています。

LINEと連携すると、会員番号とLINEのユーザーIDを結びつけて保存します。
使い道は、レッスン前日のご案内、予約の変更・キャンセルのご連絡、教室からのお知らせです。
広告の配信や、教室以外への提供には使いません。
連携はマイページの「LINE連携を解除」から、いつでも解除できます。
会員を退会すると、LINEとの連携も解除され、退会したことがLINEヤフー株式会社に通知されます。

最後の2行は、LINEログイン開発ガイドラインの必須事項に合わせたものです。LINEログインを組み込んだサイトから会員が退会するときや、連携を解除するときは、権限を取り消すエンドポイントでその人の代わりに権限を取り消し、何が起きるかを機能のそばか規約に書くことになっています。

curl -X POST https://api.line.me/user/v1/deauthorize \
  -H 'Authorization: Bearer YOUR_CHANNEL_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{ "userAccessToken": "USER_ACCESS_TOKEN" }'

Authorization に入れるのは、有効期間を指定できるチャネルアクセストークン(v2.1)か、ステートレスチャネルアクセストークンです。成功すると 204 が返り、利用者がすでに自分で連動を解除していた場合などは 400 が返ります。ここで要るのは利用者のアクセストークンなので、LINEログインで結んだ会員の分は、退会のときに取り消せるように保存しておくか、退会の操作の中でもう一度LINEログインしてもらいます。ログアウトのときにアクセストークンを取り消すなら POST https://api.line.me/oauth2/v2.1/revoke です。利用者自身は、LINEの「ホーム」→「設定」→「アカウント」→「連動アプリ」から連動を解除できます。

アカウント連携でも、いつでも解除できるようにしておくことと、連携するときに解除できると伝えることが公式に求められています。会員台帳の状態を 解除 にして送り先から外し、リッチメニューを連携前のものに戻します。

ほかに決めておくのは2つです。1つは保存期間で、退会した会員のユーザーIDは消す日を決めておきます。もう1つは見られる人で、会員台帳のLINEユーザーIDの列を、送信の仕組みと担当者だけが見られるようにします。

応用

連携の状態でリッチメニューを切り替えると、連携の案内を出し続けずに済みます。Messaging APIでは人ごとにリッチメニューを付け替えられるので、連携前の人には「会員連携」のボタン、連携済みの人には「予約の確認」「LINE連携を解除」のボタンを出します。公式もこの使い方を例に挙げています。

LIFFを使うと、LINEの中で開く予約フォームが開いた人のユーザーIDを持てるので、フォームに入れた会員番号とその場で結べます。LIFFアプリはLINEログインのチャネルの「LIFF」タブで追加し、1つのチャネルに30件まで置けます。LIFFアプリの設定にも友だち追加オプション(On (normal)、On (aggressive)、Off)があります。ただ、公式はLIFFをLINEミニアプリに統合する予定を出していて、新しく作るならLINEミニアプリとして作るよう勧めています。どちらを選ぶかは「LINEミニアプリとLIFF:何が違い、自社に要るか」で比べています。

LINEログインのチャネルの「LIFF」タブで、友だち追加オプションを選ぶところ
LINEログインのチャネルの「LIFF」タブで、友だち追加オプションを選ぶところ

自分でサーバーを書かずにLIFFのフォームを使いたいなら、拡張ツールに任せる手もあります。オープンソースのL Harnessは本体の利用料が0円で(公式アカウントの配信料やCloudflareなどの費用は別)、LINEの中で完結するフォームをLIFFで持ち、回答を友だちの情報に保存できます。会員台帳がkintoneにあるなら、結んだユーザーIDとやりとりを顧客管理に入れる流れを「LINEとkintoneをつなぐ:友だちとやりとりを顧客管理に入れる」に書いています。

できないことと、その代わり

できないこと理由代わりの手
LINE Official Account Managerの設定だけで会員と結ぶ標準機能に連携の仕組みがないアカウント連携か、LINEログインを小さなサーバーで受ける
別のプロバイダーのチャネルで取ったユーザーIDに送るユーザーIDがプロバイダーごとに違う同じプロバイダーにチャネルを作り直し、連携をやり直してもらう
公式アカウントのプロバイダーをあとから変えるMessaging APIを有効にしたときに選んだものは変えられない最初に自社名のプロバイダーを選ぶ
友だちでない人にアカウント連携の案内を送るアカウント連携は友だちが前提会員サイトにLINEログインと友だち追加オプションを付ける
申請なしでメールアドレスを取るemail スコープは事前の申請が要る会員台帳のメールアドレスを使う。要るなら申請する
PC版LINEで自動ログインさせる自動ログインはスマートフォン版LINEだけPCではQRコードかメールアドレスでのログインを案内する
連携トークンを使い回す10分で切れ、1回しか使えない連携のたびに発行し直す

よく詰まるところ

症状原因直し方
ログインで取ったユーザーIDに送ると届かないLINEログインとMessaging APIのチャネルが別のプロバイダーにある同じプロバイダーにLINEログインのチャネルを作り直す
「リンクされたLINE公式アカウント」に公式アカウントが出ないプロバイダーが違うか、操作している人が公式アカウントの管理者でないMessaging APIチャネルのプロバイダーを確かめ、管理者権限のある人が操作する
スタッフ以外がログインできないチャネルが「開発中」のまま動きを確かめてから「公開済み」に変える
ログインボタンを押してもコールバックURLに戻らないclient_id か redirect_uri が間違っているとリダイレクトされない「LINEログイン設定」に登録したURLと一字一句同じにする
トークンの交換で失敗する認可コードの10分が過ぎたか、同じコードを2回使ったコールバックを受けたらすぐ交換する。再読み込みで二度送らない
IDトークンの検証で IdToken expired.期限切れのIDトークンを後から検証しているログイン直後に検証し、結果のユーザーIDだけ保存する
IDトークンの検証で Invalid IdToken Audience.client_id に別のチャネルのIDを入れたLINEログインのチャネルIDを入れる。Messaging APIのチャネルIDではない
id_token が返ってこないscope に openid がないscope=profile%20openid にする
アカウント連携イベントが届かない連携トークンが期限切れか使用済みトークから「会員連携」を押し直してもらい、新しいトークンで送る
link.result が failed になる連携URLを、トークンを発行された本人以外が開いた連携URLを転送しないよう案内する。本人の端末でやり直す
nonce から会員番号が引けないBase64の + や / をエンコードせずURLに載せたencodeURIComponent してからリダイレクトする
Webhookの署名が一致しないパース後のJSONで計算した。チャネルシークレットを再発行した生のボディで計算する。新しいシークレットに差し替える
ログインのたびに「ログインしました」というトークが届くと問い合わせが来るLINEログインをすると、LINEからログイン通知が届く案内文に「ログインするとLINEから通知が届きます」と書いておく
負荷テストのあとに 429 が返るLINEプラットフォームへの大量リクエストは禁止されている負荷テストはLINEに投げない環境で行う

ログインと連携の記録は、自分で残します。LINE側に問い合わせても、認可リクエストやAPIのログは出してもらえません。認可リクエストの時刻とパラメータ、受け取った認可コードかエラー、APIのレスポンスヘッダーの x-line-request-id とステータスコードを、一定期間残しておくと原因を追えます。

次にやること

  • Messaging APIの始め方:チャネル・アクセストークン・Webhook
  • 予約のリマインドをLINEで自動送信する:前日・当日の通知と無断キャンセル対策
  • LINEミニアプリとLIFF:何が違い、自社に要るか
  • LINEとkintoneをつなぐ:友だちとやりとりを顧客管理に入れる

あわせて読む