Supabase との統合
Logto と Supabase を統合して、アプリケーションの認証体験を向上させる方法を学びましょう。
Logto は、セキュアで包括的かつユーザーフレンドリーなログインサポートを提供するモダンなアイデンティティ認証サービスです。また、複数のフレームワークやプログラミング言語に対応した膨大な SDK や統合ガイドを提供し、エンタープライズグレードのアイデンティティ認証サービスを数分でアプリケーションにシームレスに統合できます。
この記事は主に、Logto と Supabase を統合する方法について詳しく説明します。
Supabase の基本
Supabase は、Postgres の行レベルセキュリティ を利用してデータアクセスの権限を管理します。簡単に言うと、データベース内のテーブルに行レベルセキュリティポリシーを作成することで、誰がそのテーブルのデータを読み取り、書き込み、更新できるかを制限し管理できます。
ここでは、データベースに「posts」という名前のテーブルがあり、次のような内容が含まれていると仮定します。
このテーブル内の user_id
フィールドは、各投稿データがどのユーザーに属するかを表します。user_id
フィールドに基づいて、各ユーザーが自分の投稿データだけにアクセスできるように制限できます。
ただし、これを実装する前に、Supabase が現在データベースにアクセスしているユーザーを識別できる必要があります。
Supabase リクエストにユーザーデータを追加する
Supabase の JWT サポートのおかげで、アプリケーションが Supabase と連携する際に、Supabase によって提供された JWT シークレットを使用してユーザーデータを含む JWT を生成できます。次に、この JWT をリクエスト時の認証ヘッダーとして使用します。Supabase はリクエストを受信すると、この JWT の有効性を自動的に検証し、その後のプロセス全体で含まれるデータへのアクセスを許可します。
まず、Supabase ダッシュボードの「Project Settings」から Supabase によって提供された JWT シークレットを取得できます:
次に、Supabase SDK を使用して Supabase にリクエストを行う際に、このシークレットを使用して JWT を生成し、これを認証ヘッダーとしてリクエストに添付します。(なお、この処理はアプリケーションのバックエンドサービス内で実行されるものであり、JWT シークレットを第三者に公開することは許されません)。
次に、Supabase ダッシュボードの SQL エディターに移動し、リクエストに含まれる userId を取得する関数を作成します:
画像に使用されたコードは次のとおりです:
コードからわかるように、Supabase では、request.jwt.claims
を呼び出すことで生成した JWT のペイロードを取得できます。ペイロード内の userId
フィールドが私たちが設定した値になります。
この関数で、Supabase は現在データベースにアクセスしているユーザーを特定することができます。
行レベルセキュリティポリシーを作成する
次に、投稿テーブル内の user_id
フィールドに基づ いて、各ユーザーが自分の投稿データだけにアクセスできるようにする行レベルセキュリティポリシーを作成することができます。
- Supabase ダッシュボードのテーブルエディターページに移動し、投稿テーブルを選択します。
- テーブルの上部にある「Add RLS Policy」をクリックします。
- 表示されたウィンドウで「Create policy」をクリックします。
- ポリシー名を入力し、SELECT ポリシーコマンドを選択します。
- 次のコードの
using
ブロックに次のように入力します:
このようなポリシーを活用することで、Supabase 内のデータアクセスの制御が実現されます。
実際のアプリケーションでは、データの挿入や変更などのユーザー操作を制限するために、さまざまなポリシーを作成することになります。ただし、これはこの記事の範囲を超えます。行レベルセキュリティ (RLS) の詳細については、Postgres 行レベルセキュリティでデータを保護する を参照してください。
Logto との基本的な統合プロセス
前述のように、Supabase はアクセス制御に RLS を使用するため、Logto(または他の認証サービス)と統合する際の鍵は、認証されたユーザーのユーザー ID を取得してこれを Supabase に送信することです。以下の図に、全体のプロセスが示されています:
次に、このプロセス図に基づいて Logto と Supabase をどのように統合するかを説明します。
Logto の統合
Logto は、さまざまなフレームワークとプログラミング言語の統合ガイドを提供しています。
通常、これらのフレームワークと言語で構築されたアプリケーションは、ネイティブアプリ、SPA(シングルページアプリ)、従来の Web アプリ、M2M(マシン・ツー・マシン)アプリなどのカテゴリに分かれます。Logto クイックスタート ページを訪れて、使用している技術スタックに基づいて Logto をあなたのアプリケーションに統合できます。その後、アプリケーションの種類に基づいて、以下の指示に従ってプロジェクトに Logto を統合します。
ネイティブアプリや SPA
ネイティブアプリと SPA の両方はデバイス上で実行され、ログイン後に取得した資格情報(アクセストークン)はデバイスにローカルで保存されます。
したがって、アプリを Supabase と統合する際には、バックエンドサービスを介して Supabase とやり取りする必要があります。これにより、各ユーザーのデバイス上でセキュアでない情報(例:Supabase JWT シークレット)を公開することを防ぎます。
React と Express を使用して SPA を構築していると仮定しましょう。Logto React SDK ガイド に従って、アプリケーションに Logto を正常に統合しました(コードについては、私たちの react sample を参照してください)。さらに、Protect your API on Node (Express) ドキュメントに従って、バックエンドサーバーに Logto のアクセストークン検証を追加しました。
次に、Logto から取得したアクセストークンを使用してバックエンドサーバーにユーザーデータをリクエストします:
バックエンドサーバーでは、ミドルウェアを使用してアクセスされたアクセス トークンからログインしたユーザーの ID をすでに抽出しています:
次に、前述の getSupabaseClient
を使用して、userId
を付与した JWT を Supabase への後続のリクエストで使用します。または、Supabase とやり取りする必要があるリクエストに対して Supabase クライアントを作成するミドルウェアを作成することもできます:
その後の処理フローでは、ctx.supabase
を直接呼び出して Supabase とやり取りできます:
このコードでは、Supabase が以前に設定したポリシーに基づいて、現在のユーザーに属する投稿データのみを返します。
従来の Web アプリ
従来の Web アプリとネイティブアプリや SPA との主な違いは、従来の Web アプリが Web サーバー上で完全にページの描画と更新を行うことです。したがって、ユーザークレデンシャルは Web サーバーによって直接管理されますが、ネイティブアプリ や SPA ではユーザーのデバイス上で管理されます。
Supabase で従来の Web アプリに Logto を統合する際には、バックエンドから直接ログインしたユーザーの ID を取得できます。
Next.js プロジェクトを例に取り上げ、Next.js SDK ガイド に従ってプロジェクトに Logto を統合した後、Logto SDK を使用してユーザー情報を取得し、Supabase とのやり取りに使用する対応する JWT を生成できます。
マシン・ツー・マシンアプリ
マシン・ツー・マシン (M2M) は、アプリケーションがリソースサーバーと直接通信する際に使用されることが多いです。例えば、毎日投稿を取得するための静的サービスなどです。
マシン・ツー・マシン: Logto での認証 ガイドを使用して、マシン・ツー・マシンアプリの認証を行います。Supabase とマシン・ツー・マシンアプリとの統合は、ネイティブアプリや SPA の統合(「ネイティブアプリやシングルページアプリ」セクションで説明しています)と類似しています。Logto から取得したアクセストークンを使用し、保護されたバックエンド API を通じて検証を行います。
ただし、ネイティブアプリや SPA は通常、エンドユーザー向けに設計されているため、取得されたユーザー ID はユーザー自体を表していることになります。しかし、M2M アプリのアクセストークンはアプリケーション自体を表し、アクセストークンのペイロード内の sub
フィールドは特定のユーザーではなく、M2M アプリのクライアント ID です。したがって、開発中にはどのデータが M2M アプリ用であるかを適切に区別することが重要です。
さらに、特定の M2M アプリが Supabase に接続して全体のサービスを代行し、RLS 制限を回避する場合、Supabase の service_role
シークレットを使用して Supabase クライアントを作成することができます。これにより、ユーザーごとに設定された行レベルのセキュリティポリシーに制限されることなく、すべてのデータにアクセスできるようになります。管理タスクや自動化されたタスクを実行する際に便利です。
service_role
シークレットは、JWT シークレットと同じページで見つけることができます:
Supabase クライアントを作成する際、この service_role
シークレットを使用すると、このクライアントがデータベース内のすべてのデータにアクセス可能になります:
まとめ
この記事では、Logto と Supabase の統合について掘り下げ、重要な洞察や統合の要点を解説しました。JWT 認証や行レベルセキュリティポリシーなどの概念を探求し、Logto を Supabase を利用したアプリケーションにシームレスに組み込むプロセスを案内しました。この知識が、アプリケーションのセキュリティや機能性を向上させるだけでなく、プロジェクトに追加の機能を拡張する自信となることを願っています。