Supabaseに入門する
概要
認証基盤としてSupabaseがどの程度使いやすいか?を調査する。
サインアップ、サインイン、GoogleなどのOpenID プロバイダーによる認証をどのように実装していくか調査する。
アカウント作成
GitHubアカウントで登録が出来るので登録する。
プロジェクト作成
next-supabase-examples という検証用プロジェクトを作ったので、とりあえずこれと同じ名前でプロジェクトを作成する。
必要事項を入力、特に難しくはない。
Planはとりあえずフリーを選択。
公式の Supabase Auth with the Next.js App Router を参照しながら進める
以下のガイドに従って進めていく。
npx create-next-app -e with-supabase
とするとプロジェクトの初期構成を作ってくれるようだ。
ただしこの生成方法で生成されたテンプレートにはいくつか問題があったので通常の create-next-app
で生成されたファイルからマージしている。
- ESLintの設定がなかったので追加(本家の
create-next-app
の結果にはある) - パッケージのバージョンが常に latest になっていたりするので、こちらはバージョン固定をした
-
tsconfig.json
のpaths
の設定が消えてしまったいたのでcreate-next-app
の結果と同じ設定に変更
具体的な変更内容は以下のPRにまとめている。
Supabase のアクセストークンをAPI認証として利用出来るか?
ServerComponents内で以下のようにすると、JWT形式のアクセストークンを取得出来た。
const supabase = createServerComponentClient({ cookies })
const token = await supabase.auth.getSession();
console.log(token);
ちなみにpayloadの形は以下のような形。
{
"aud": "authenticated",
"exp": 1689956112,
"iat": 1689952512,
"iss": "https://https://xxxxxxx.supabase.co/auth/v1",
"sub": "UUIDv4形式",
"email": "keita@exmple.com",
"phone": "",
"app_metadata": {
"provider": "email",
"providers": [
"email"
]
},
"user_metadata": {},
"role": "authenticated",
"aal": "aal1",
"amr": [
{
"method": "password",
"timestamp": 1689952512
}
],
"session_id": "UUIDv4形式"
}
このJWTを検証すれば、自作で作ったAPIサーバー等でもこの値を認証・認可に利用出来そう。
Supabaseのアクセストークンを検証
以下は jose を使って検証を実施している例。(実行しているのはAppRouterのServerComponents内)
import { cookies } from 'next/headers';
import * as jose from 'jose';
const supabase = createServerComponentClient({ cookies });
const token = await supabase.auth.getSession();
const secretKey = new TextEncoder().encode(
'https://supabase.com/dashboard/project/{自分のプロジェクトID}/settings/api 内からコピーしたJWT Secretを設定',
);
const jwtVerifyResult = await jose.jwtVerify(String(token.data.session?.access_token), secretKey, {issuer: 'https://https://{自分のプロジェクトID}.supabase.co/auth/v1'});
console.log(jwtVerifyResult);
もちろん自作したAPIサーバー内でも標準的な機能を備えたJWT用ライブラリを使って検証を実施出来る。
例えばPython + LangChain + FastAPIで作成した自作API内でもSupabaseのアクセストークンを利用してアクセス制御を行う事が可能。
Googleログインの実装
以下を見ながら実装していく。
Supabase の以下のURLからGoogleによる認証を有効化する。
project-id
には実際のプロジェクトIDが入る。
https://supabase.com/dashboard/project/{project-id}/auth/providers
管理画面のメニューの Authentication → Providers から遷移する。(UIが変わる可能性はアリ)
OAuthの情報を入力する必要があるので、Google CloudのAPIとサービス → 認証情報から OAuth 2.0 クライアント ID を作成する。(Callback URLは後でGoogle Cloud側で使うのでコピーしておく)
Client IDとClient Secretをコピーして Supabase 側で以下の情報を入力して事前準備完了。
- Client ID (for OAuth)
- Client Secret (for OAuth)
- Authorized Client IDs これは空でOK。
以下は実装時のPR。
最初はReactServerComponents内で supabase.auth.signInWithOAuth
を使ってGoogleログインの実装を試みたが invalid request: both auth code and code verifier should be non-empty
というエラーが発生してしまい上手くいかなかった。
これはissueが報告されており、どうやらNext.js側の問題らしい。
仕方がないのでGoogleログイン用のButtonComponentを作って onClick
時に実行する方法を取った。
ちなみに認証成功時のアクセストークンのpayloadは以下のような感じだ。
emailログインの時よりも情報量が多くpayloadからGoogleアカウントの情報が取得出来るようになっている。
{
"aud": "authenticated",
"exp": 1690123901,
"iat": 1690120301,
"iss": "https://https://xxxxxxx.supabase.co/auth/v1",
"sub": "UUIDv4形式",
"email": "Gmailのメールアドレス",
"phone": "",
"app_metadata": {
"provider": "google",
"providers": [
"google"
]
},
"user_metadata": {
"avatar_url": "アバター画像のURL",
"email": "Gmailのメールアドレス",
"email_verified": true,
"full_name": "ユーザー名のフルネーム",
"iss": "https://accounts.google.com",
"name": "ユーザー名",
"picture": "エンドユーザーの画像URL",
"provider_id": "数値(型は文字列)",
"sub": "数値(型は文字列)"
},
"role": "authenticated",
"aal": "aal1",
"amr": [
{
"method": "oauth",
"timestamp": 1690120301
}
],
"session_id": "UUIDv4形式"
}
ちなみに先にメールアドレスとパスワードで登録して同じGmailのアカウントを使ってGoogleログインを実行すると同じユーザーと見なしてくれる。
逆に先にGoogleログインで登録して後でパスワードとemailで登録しようとすると、重複していると見なされてしまい、登録APIでエラーが発生してしまった。
同一のメールアドレスで登録している他のソーシャルアカウント(例えばFacebookとか)で登録を試みた場合はどうなるのかが気になる。
細かい問題
無料版だとGoogleログイン時の同意画面に自分の supabase
のプロジェクトのDomainが表示されてしまう。
ここを独自Domainにしたい場合は有料プランを契約してCustomDomainsの設定をする必要がある。
Supabaseの良いと思った点
- 安いのに高機能、認証基盤としての機能は十分で認証の履歴等も閲覧可能
- パスワードレス認証(マジックリンクによるログインやSMS認証に対応)に対応している
- ドキュメントが充実している
- RDBが付いているのは嬉しい
Supabaseのちょっと残念なところ
- 対応しているソーシャルログインが少ない + B to B向けの物が多い
ちなみに対応しているソーシャルログインは以下の通り。
今後実装される可能性もあるが現状だとカスタムAuthもないので、LINEログイン等は実装出来ない。
今回は要件としてLINEログインが必須だったので残念ながら不採用とした。
とは言えサービスのポテンシャルはかなり感じたので、今後別の機会にいつか使ったみたい。