Loading...

2023-12-06(水) 15:00

🏁 LINE Messaging APIのWebhookをSupabase Edge Functionsで実装する

SupabaseLINE
LINE Messaging APIのイベントを受け取るためのWebhookをSupabase Edge Functionsで実装する手順を解説します。

目次

この記事のゴール

LINE の友達追加やメッセージ受信など LINE Messaging API でのイベントを Supabase Edge Functions で受け取るための Webhook を受け取るまでをゴールとします。

前提と注意事項

この記事では以下を前提としています。

  • LINE Developers アカウントを作成済みであること。
  • Supabase アカウントを作成済みで Supabase CLI を使える環境であること。

Supabase Edge Functions を作成する

LINE Messaging API のイベントを受け取るための Supabase の Edge Function を Supabase CLI を使って作成します。
ここでは、linebotという名前の Edge Function を作成します。

ターミナル
$ supabase functions new linebot

実行結果

ターミナル
$ supabase functions new linebot
Created new Function at supabase/functions/linebot

supabase/functions/linebotを以下のようにします。

supabase/functions/linebot
console.log('Hello from LINE bot Functions!');
 
// 署名検証用のチャネルシークレット
const LINE_MESSAGING_API_CHANNEL_SECRET = Deno.env.get(
  'LINE_MESSAGING_API_CHANNEL_SECRET',
);
 
// LINE Messaging APIのチャネルトークン
// メッセージを受信して返信する場合などに使用する
const LINE_MESSAGING_API_CHANNEL_TOKEN = Deno.env.get(
  'LINE_MESSAGING_API_CHANNEL_TOKEN',
);
 
// HMAC-SHA256の署名を作成する関数
async function createHMAC(secret: string, message: string): Promise<string> {
  const encoder = new TextEncoder();
  const keyData = encoder.encode(secret);
  const msgUint8 = encoder.encode(message);
 
  const key = await crypto.subtle.importKey(
    'raw',
    keyData,
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign'],
  );
 
  const signature = await crypto.subtle.sign('HMAC', key, msgUint8);
  return btoa(String.fromCharCode(...new Uint8Array(signature)));
}
 
Deno.serve(async (req) => {
  // リクエストヘッダーに含まれる署名を取得
  const _headerSignature = req.headers.get('x-line-signature');
  const _body = await req.text();
  const _data = JSON.parse(_body);
 
  // リクエストボディの署名を作成
  const _bodySignature = await createHMAC(
    LINE_MESSAGING_API_CHANNEL_SECRET,
    _body,
  );
 
  // 署名が一致するかを確認してリクエスト元がLINEであるかを検証する
  // 署名失敗時は401エラーを返す
  if (_headerSignature !== _bodySignature) {
    console.log('Unauthorized');
    return new Response('Unauthorized', { status: 401 });
  }
 
  // LINEからのイベントは複数含まれる場合があるため、
  // それぞれのイベントに対して処理を行う
  for (const event of _data.events) {
    // メッセージイベント
    if (event.type == 'message') {
      console.log('Message event');
 
      // テキストメッセージ
      if (event.message.type == 'text') {
        console.log('Text Message event');
      } else {
        console.log('Not Text Message event');
      }
 
      // 友だち追加イベント
    } else if (event.type === 'follow') {
      console.log('Follow event');
 
      // 友だちブロックイベント
    } else if (event.type === 'unfollow') {
      console.log('Unfollow event');
 
      // その他のイベント
      // https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects
    } else {
      console.log('event here');
      console.log(event.type);
    }
  }
 
  return new Response('OK');
});

上記は、リクエスト元が本当に LINE からであるかの検証を行い、検証成功時にはイベント毎にconsole.logを実行するだけのものです。
実際には、各イベントに応じてメッセージに返信したり、Supabase のデータベースにデータを書き込んだりします。

リクエスト元の検証方法については、以下の LINE Messaging API の公式リファレンスにある通り、HMAC-SHA256 を使った検証を行っています。

署名を検証する

リクエストがLINEプラットフォームから送られたことを確認するために、ボットサーバーでリクエストヘッダーのx-line-signatureに含まれる署名を検証します。

developers.line.biz

上記の Edge Functions では、createHMACという関数を作ってそれを使って署名を生成しています。Deno での署名生成については別途以下にまとめましたので必要な方は見てみてください。

🦖 DenoでHMAC-SHA256を使ってリクエストの署名を検証する

DenoでWeb APIなどリクエスト元の検証のためにHMAC-SHA256を使ってリクエストの署名を検証する方法を解説します。

ritaiz.com

なお、LINE Messaging API で受け取るイベントの仕様については以下の公式ドキュメントに記載されています。

Webhookイベントオブジェクト

LINEプラットフォームで生成されるイベントを含むJSONオブジェクトです。

developers.line.biz

チャネルシークレットを環境変数に設定する

前述したようにリクエスト元の検証のために、HMAC-SHA256 を使った検証を行っています。 この検証に使用するシークレットは、LINE Developers の Messaging API のチャネル基本設定タブの中にあります。

チャネル基本設定ページ

チャネル基本設定タブページの下の方にスクロールすると以下のように チャネルシークレットという項目があります。

チャネルシークレット

この値をコピーして、以下を実行することで Supabase Edge Functions 内で使用できるシークレットとして設定します。

シークレットを保存する
$ supabase secrets set LINE_MESSAGING_API_CHANNEL_SECRET=1928019j8k192aa19d60cea0ea9d6199at

実行結果

シークレットを保存する
$ supabase secrets set LINE_MESSAGING_API_CHANNEL_SECRET=1928019j8k192aa19d60cea0ea9d6199at
Finished supabase secrets set.

デプロイする

以下を実行してデプロイします。

デプロイする
$ supabase functions deploy linebot --no-verify-jwt
Version 1.30.3 is already installed
Bundling linebot
Deploying linebot (script size: 101kB)
Deployed Function linebot on project iqjduehnshcuentoie
You can inspect your deployment in the Dashboard: https://supabase.com/dashboard/project/iqjduehnshcuentoie/functions/linebot/details

Webhook を登録、検証する

LINE Developers で Webhook に、デプロイした Supabase Edge Functions の URL を登録し、検証します。 まず、以下のようにMessaging API設定の中にあるWebhook設定編集ボタンをクリックします。

LINE Messaging APIの設定ページ Webhook URLの設定ページ

編集ボタンをクリックすると以下のように Webhook URL の入力フォームが表示されるので、ここに前述した Supabase Edge Functions の URL を入力し、更新ボタンをクリックします。

Webhook URLの設定ページ

以下のように Webhook URL が設定されます。ここで検証ボタンをクリックします。

Webhook URLの検証

以下のように成功というダイアログが表示されれば正常に Webhook がデプロイされてかつ LINE 側からもアクセスできる状態です。

Webhook URLの検証成功時

もし、検証をクリックして以下のような内容が表示される場合は、エラーが発生しているため、Supabase Edge Functions のログを確認してみてください。

Webhook URLの検証失敗時

なお、上記の画像は500 Internal Server Errorですが、これが401 Unauthorizedの場合は署名の検証に失敗しているか、検証のための処理に問題がある可能性が高いです。

動作確認する

あとは適当な LINE アカウントから友達追加を行って動作確認を行います。友達追加するには、通常の LINE の友だち追加と同じように、以下のようにMessaging API設定の中にあるQRコードを LINE アプリで読み込んで友だち追加すれば OK です。

LINEアプリで友だち追加する

友だち追加やメッセージを送信した後、以下のようにSupabase Edge Functionsページにある LINE Messaging API 用に作成した Edge Function (画像内のlinebot)をクリックします。

Supabase Edge Functionsのログを確認する

以下のようにLogsタブにイベントのログが出力されるていることを確認できるはずです。

Supabase Edge Functionsのログ例

まとめ

LINE Messaging API 用の Webhook を Supabase Edge Functions で実装しました。この記事では各イベントに応じた処理はしていませんが、ユーザーからのメッセージ内容やイベントに応じて Supabase と連携していろいろなことができます。