匿名認証 1 Supabase 匿名認証メモ #認証 - Qiita
匿名認証 2 Next.js 14 のServer Actions を利用した、Supabaseの匿名認証の最低限な実装 #ServerActions - Qiita
Supabase 匿名認証メモ
Supabase匿名認証のドキュメントなどをベースにAIにかけたメモ
公式Blogより
created: 2024-04-18T23:46:43 (UTC +09:00)
tags: []
source: https://supabase.com/blog/anonymous-sign-ins
author:
Supabase Auth が匿名サインインをサポートします。
Supabase Auth が、 匿名サインインに対応しました
Supabase Auth が、コミュニティから最もリクエストの多かった機能の一つである匿名サインインをサポートしました。
匿名サインインは、まだアプリケーションにサインアップしていない 仮のユーザ を作成するために使用できます。これは、新規ユーザーがサインアップの認証情報を提供する必要がないため、ユーザーが製品を試す手間を減らすことができます。
.匿名サインインを有効にする
ダッシュボードから、あなたのプロジェクトに匿名サインインを有効にすることができます。
匿名サインインを許可する
Settings | Supabase
https://supabase.com/dashboard/project/_/settings/auth
Allow anonymous sign-ins
をオンにします。
警告
匿名ユーザは、サインイン時に認証済みロールを使用します。
その結果、匿名ユーザーには、公開ロールおよび認証ロールに適用される RLS ポリシーが適用されます。お客様のデータへのアクセスが必要に応じて制限されるように、RLS ポリシーを見直すことを強くお勧めします。
匿名ユーザーに認証済みの役割が割り当てられてしまうので、匿名ユーザーに色々アクセス出来てしまうので、RLSでコントロールしてください。
ローカルで開発する場合は、Supabase CLI をアップグレードし、config.toml
ファイルに設定を追加します。
Supabase CLIのアップデート
scoop update supabase
[auth]
enable_anonymous_sign_ins = true
現在のconfig.tomlの[auth]項目
supabase\config.toml
[auth]の項目だけ抜粋
enable_anonymous_sign_ins 匿名認証
# Allow/disallow anonymous sign-ins to your project.
enable_anonymous_sign_ins = true
trueに設定します。
匿名認証を有効にするために ture
に設定しておく必要があります。
enable_manual_linking 匿名から正規ユーザーへの切り替え
# Allow/disallow testing manual linking of accounts
enable_manual_linking = true
trueに設定します。
匿名から正規ユーザーへの切り替えを有効にするために ture
に設定しておく必要があります。
[auth]
enabled = true
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
# in emails.
site_url = "http://127.0.0.1:3000"
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
additional_redirect_urls = ["https://127.0.0.1:3000"]
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
jwt_expiry = 3600
# If disabled, the refresh token will never expire.
enable_refresh_token_rotation = true
# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
# Requires enable_refresh_token_rotation = true.
refresh_token_reuse_interval = 10
# Allow/disallow new user signups to your project.
enable_signup = true
# Allow/disallow anonymous sign-ins to your project.
enable_anonymous_sign_ins = true
# Allow/disallow testing manual linking of accounts
enable_manual_linking = true
※最下段に2つ追加されています。
Javascript SDKから匿名ユーザーを作成することができます。
以下は supabase-js
を使って匿名ユーザーを作成する方法です。
const { data, error } = await supabase
.auth
.signInAnonymously()
SDK
software development kit
用語
匿名サインインで作成されたプロファイルも authenticated
です。
.signInAnonymously()
を呼び出すと、ユーザーが認証フローに移動しサインインしたユーザーと同じように扱われるようになります。
匿名ユーザのアクセス制限
正規ユーザーと同様に、匿名ユーザーは auth.users
テーブルに保存されます。
id | role | is_anonymous | |
---|---|---|---|
e053e470-afa1-4625-8963-37adb862fd11 | authenticated | NULL | true 👈 |
5563108e-ac81-4063-9288-4f3db068efa1 | 認証済み | luke@starwars.com | false |
匿名ユーザーは、ユーザーの JWT で返される is_anonymous
クレームによって識別することができます。これは、アプリケーションの特定の機能へのアクセスを制限したい場合に便利です。
is_anonymous
クレームとは、
JWTから取得できるデータ値で、匿名ユーザーの場合に true
が返されます。
匿名ユーザーは、ユーザーのJWTから取得される is_anonymous
クレームによって識別できます。
このクレームは、行レベルセキュリティポリシー(RLS)からアクセス可能です。
これは、アプリケーション内の特定の機能へのアクセスを制限したい場合に役立ちます。
例えば、ユーザが投稿を作成したり読んだりできるオンラインフォーラムがあるとします。
投稿を保存するテーブルとして、以下のようなものがあるとします。
create table public.posts (
id serial primary key,
name text not null,
description text
);
正規ユーザーにのみ投稿の作成を許可したい場合、JWT を調べてユーザーが匿名かどうかを判断します。
select auth.jwt() ->> 'is_anonymous'
この関数を RLS ポリシーで使用します。
create policy "Only permanent users can create posts"
on public.posts
for insert
to authenticated -- Note: user is still authenticated
with check (
(select auth.jwt() ->> 'is_anonymous')::boolean is false
);
RLS では、さまざまなルールを柔軟に作成することができます。
例えば、
正規ユーザーにはすべての投稿の読み込みアクセスを許可します。
匿名ユーザーには今日作成された投稿に限定します。
といった具合です。
create policy "Limit access to anonymous users"
on public.posts
for select
to authenticated -- Note: user is still authenticated
using (
case
when (select (auth.jwt() ->> 'is_anonymous'))::boolean is true
then (created_at >= current_date)
else
true
end
);
匿名ユーザーを正規ユーザーにリンクする
ある時点で、匿名ユーザーは投稿を作成したいと思うかもしれません。
このような場合、アカウントへのサインアップを促し、正規ユーザにリンクします。
Supabase Auth ではこれを実現する 2つの方法 が用意されています。
- Eメールまたは電話番号とリンクする
- OAuth IDをリンクする
OAuth ID をリンクするとは、匿名ユーザーが既存の外部アカウント(Google、Facebook、X(Twitter) など)を使用して、正規ユーザーのアカウントを作成できます。
1. メールや電話の ID をリンクする
メールや電話のIDをリンクするには
const { data, error } = await supabase
.auth
.updateUser({ email })
2. OAuth ID をリンクする
OAuth ID を匿名ユーザーにリンクするには、プロジェクトで 手動リンクを有効にする 必要があります。Supabase AuthでのIDリンクの動作についてはこちらをご覧ください。
Settings | Supabase
有効化したら、 linkIdentity()
メソッドを呼び出します。
const { data, error } = await supabase
.auth
.linkIdentity({ provider: 'google' })
匿名ユーザーへのなりすまし (RLSでのテスト用)
匿名ユーザーのアクセスを区別するために RLS ポリシーを作成する場合、SQL エディターの ユーザーなりすまし機能 を活用してポリシーをテストすることができます。
SQLエディタで匿名ユーザーのアクセス制限をテストする方法
RLSポリシーを作成して匿名ユーザーのアクセスを区別する場合、SQLエディタのユーザー impersonation 機能を利用して、ポリシーをテストできます。
偽ユーザーを作って、匿名ユーザーになりすまし、ポリシーが正しく動作するか確認できます。
SQLエディタのデータベースロール設定。ドロップダウンからユーザーを選択することで、匿名ユーザーになりすますことができます。
ユーザー管理画面には、匿名ユーザーでフィルタするオプションがあり、作成された匿名ユーザーの数を知るのに役立ちます。
ユーザーページでの匿名ユーザーによるフィルタリング。
次は何をすればいいですか?
匿名ユーザーの管理は、特にサイトへの訪問者が多い場合、厄介です。
現在30日以上アクティブでない匿名ユーザーを削除するための "自動クリーンアップ "オプションを開発中です。
それまでは、匿名ユーザーはデータベースのauthスキーマに保存されつづけてしまいますが、以下のクエリを実行することで、孤立した匿名ユーザーを (正規ユーザーに紐づけられていない)削除することができます。
-- 30日以上前に作成された匿名ユーザーを削除する
delete from auth.users
where is_anonymous is true and created_at < now() - interval '30 days';
※↑手動でこのsqlを実行してください。
また、RLS ポリシーをチェックし、匿名ユーザーのアクセスを許可しているポリシーをハイライトする linter も開発中です!
匿名サインインについてはじめる
匿名サインイン | Supabase ドキュメント
Supabase Javascript クライアント - 匿名ユーザーの作成
公式ドキュメントより
created: 2024-04-19T00:20:07 (UTC +09:00)
tags: []
source: https://supabase.com/docs/guides/auth/auth-anonymous
author:
今回の認証は匿名認証
ユーザー有りのアプリを作るとして、👇こんな役割を振り分ける時に使用します。
例
役割(ロール) | 認証 | 制限 |
---|---|---|
匿名ユーザー | 未認証 | READ ONLY |
匿名ユーザー | 匿名認証 👈 | 大: 30日後に削除(自動) |
正規無料ユーザー | 正規認証 | 中 |
正規有料ユーザー | プレミア認証 | 小 |
管理者 | 管理人認証 | 無し |
匿名サインイン | Supabase Docs
要約
匿名サインインを有効にすると、メールアドレスやパスワードの入力、OAuth プロバイダの使用、その他の PII (個人を特定できる情報) の提供を必要とせずに、ユーザーに認証された体験を提供するアプリを構築できます。後で準備ができたら、ユーザーは自分のアカウントに認証方法をリンクすることができます。
匿名ユーザーを作成し、Supabaseで認証する
匿名サインインを有効にすることで、
メールアドレスやパスワードなどの個人情報を入力することなく、ユーザー認証を実現できます。
後で準備ができたら、ユーザーは認証方法を自分のアカウントにリンクさせることができます。
匿名ユーザーとanonキーの比較
signInAnonymously()
を呼び出すと、匿名ユーザーが作成されます。
これは正規ユーザと同じですが、サインアウトしたり閲覧データを消去したり別のデバイスを使用したりすると、そのユーザは自分のアカウントにアクセスできなくなります。
PII
Personally Identifiable Information
個人を特定できる情報
正規ユーザーと同様に、認証されたPostgresロールは、データAPIを使用してプロジェクトにアクセスする際に使用されます。
これらのユーザーのJWTは、RLSポリシーで区別するために使用できる is_anonymous
クレームを持ちます。
クレームというのは?
セキュリティや認証の文脈で使用される用語で、ある主体(通常はユーザー)に関する情報を含むデータのことを指します。
JWT(JSON Web Token)や他の認証トークン内にこのクレームの値が含まれており、ユーザーの属性や権限、その他の関連する情報を定義します。
例えば、is_anonymous
クレームは、ユーザーが匿名であるかどうかを示す情報です。
他の一般的なクレームには、ユーザーのIDや役割、有効期限などが含まれます。
これらのクレームは、アプリケーションがユーザーを認識し、権限を付与するために使用されます。
要するに、クレームは認証トークン内の情報であり、ユーザーの特性や状態を表すために利用されます。
認証されたユーザーは、データベース内の情報にアクセスする際に特定の権限を持ちます。
RLSポリシーとは、データベース内の情報へのアクセスを制御するためのルールのことです。
その中で、 is_anonymous
クレームは、ユーザーが匿名であるかどうかを示す情報です。
つまり、このクレームが true
の場合、ユーザーは匿名ユーザーであり、特定の権限が与えられているかどうかに基づいてデータベースにアクセスできます。
これにより、匿名ユーザーと通常のユーザーを区別して、それぞれに適切なアクセス権を付与することができます。
正規ユーザと同様に、認証されたPostgresロールは、データAPIを使用してプロジェクトにアクセスする時に使用されます。
これらのユーザの JWT は、RLS ポリシーで区別するために使用できる is_anonymous
クレームを持ちます。
これは、ユーザーを作成しない anon API キーとは異なり、
匿名という Postgres ロールを使用するため、データベースへのパブリックアクセスを実装するために使用できます。
匿名サインインは、次のような構築に使用できます。
- チェックアウト前のショッピングカートなどのEコマースアプリケーション
- 個人情報を収集しない全機能デモ
- 一時的または使い捨てのアカウント
匿名サインインを有効にする前、既存の RLS ポリシーを確認してください。
匿名ユーザーは認証されたロールを使用します。
匿名ユーザーと正規ユーザーを区別するには、ポリシーでユーザーの JWT の is_anonymous フィールドをチェックする必要があります。
↓詳細については、アクセス制御のセクションを参照してください。
Anonymous Sign-Ins | Supabase Docs
セルフホスティングとローカル開発
セルフホスティングでは、提供されたファイルと環境変数を使用してプロジェクトの設定を更新できます。
↓詳細はローカル開発のドキュメントをご覧ください。
Supabase CLI config
匿名でサインインする
signInAnonymously()
メソッドを呼び出します。
匿名ユーザーの作成
新しい匿名ユーザーを作成します。
匿名ユーザーを返す
悪用を防ぐために、匿名でのサインインにはキャプチャを設定することを推奨します。
オプションパラメータに captcha トークンを渡します。
Parameters
credentials
Optional
SignInAnonymouslyCredentials
キャプチャ
※人間であるかの判断を行います。
Enable Captcha Protection | Supabase Docs
👆 Supabaseには キャプチャ ツールが用意されています。
コラム: キャプチャとは?
キャプチャとキャプチャトークン
キャプチャトークンは、reCAPTCHA というシステムで生成されるトークンです。reCAPTCHAは、Webサイトをボットなどの不正アクセスから守るための仕組みです。
たとえば、reCAPTCHA v3 では、ユーザーがボットかどうかを判断するために、目に見えない課題を課す代わりに、ユーザーの行動を分析します。
分析結果に基づいて、リスクスコアと呼ばれる数値が生成されます。リスクスコアが高い場合は、ユーザーにキャプチャを表示して、人間であることを証明させるようにします。
キャプチャトークンは、このキャプチャを完了したことを証明するために使用されます。reCAPTCHA v3 を利用する場合は、SignInAnonymouslyCredentials にキャプチャトークンを渡すことで、匿名ユーザーを作成することができます。
キャプチャトークンを使用することで、不正なアカウント作成を防止することができます。
例
const { data, error } = await supabase.auth.signInAnonymously({
options: {
captchaToken
}
});
//---
const { data, error } = await supabase.auth.signInAnonymously({
options: {
data
}
})
//---
const { data, error } = await supabase.auth.signInAnonymously()
匿名ユーザーを正規ユーザーとリンクする
匿名ユーザを正規ユーザとリンクするには、そのユーザに IDをリンクする 必要があります。
このためには、Supabaseプロジェクトで 手動リンクを有効にする 必要があります。
方法は2種類あります。
1. メール/電話IDのリンク
updateUser()
メソッドを使用すると、匿名ユーザーにメールや電話のIDをリンクすることができます。
匿名ユーザーにパスワードを追加するには、まずユーザーの電子メールまたは電話番号を確認する必要があります。
const { data, error } = await supabase.auth.updateUser({ email: 'example@email.com' })
// 電子メール変更リンクをクリックして、ユーザーの電子メールを確認する。
// または、メールアドレスに送信された6桁のOTPを入力する。
// once the user has been verified, update the password
const { data, error } = await supabase.auth.updateUser({ password: 'password' })
※OTP
One Time Password
ワンタイムパスワード
2. OAuth ID をリンクする
匿名ユーザーに OAuth ID をリンクするには、
linkIdentity()
メソッドを使用します。
例 google認証とのリンク
const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
アクセス制御
匿名ユーザーは正規ユーザーと同じように authenticated
ロールを引き受けます。
行レベルセキュリティ (RLS) ポリシーを使用して、auth.jwt()
が返す JWT の is_anonymous
クレームをチェックすることで、匿名ユーザーと正規ユーザーを区別することができます。
create policy "Only permanent users can post to the news feed"
on news_feed as restrictive for insert
to authenticated
with check ((select (auth.jwt()->>'is_anonymous')::boolean) is false );
create policy "Anonymous and permanent users can view the news feed"
on news_feed for select
to authenticated
using ( true );
制限的ポリシーの使用
通常、RLSポリシーは「OR」で結合されます。つまり、複数のポリシーが設定されていても、どちらか一方の条件を満たせばアクセスできます。
しかし、匿名ユーザーなど特定のユーザーに対しては、常に厳しい制限をかけたいですよね。そのためには、「AND」で結合される制限ポリシー を作るのがポイントです。
「AND」ポリシーは、すべての条件を満たさない限りアクセスできないように設定します。
こうすることで、他の緩いポリシーと一緒に使われても、匿名ユーザーのアクセスを確実に制限できるようになります。
PostgreSQL RLS によるニュースフィードへのアクセス制御
このコードは、PostgreSQLで "news_feed" というテーブルへのアクセスを制御する 2 つのポリシーを作成します。
これらのポリシーは、誰がニュースフィードに投稿できるか、誰が閲覧できるかを決定します。
1. "Only permanent users can post to the news feed"
このポリシーは、ニュースフィードへの投稿を許可するユーザーを制限します。 具体的には、以下の条件を満たすユーザーだけが投稿できます。
- 認証済みであること
- 匿名ユーザーではないこと
このポリシーは、認証済みユーザーの JWT トークンをチェックすることで、ユーザーが匿名であるかどうかを判断します。 トークンに is_anonymous
というクレームがあり、それが false
である場合のみ、ユーザーは投稿できます。
2. "Anonymous and permanent users can view the news feed"
このポリシーは、ニュースフィードを閲覧できるユーザーを許可します。 具体的には、以下の条件を満たすユーザーが閲覧できます。
- 認証済みであること
このポリシーは、認証済みユーザーであれば誰でも閲覧を許可します。 匿名ユーザーも含みます。
このコードの詳細
-
create policy
: 新しいアクセス制御ポリシーを作成します。 -
"Only permanent users can post to the news feed"
and"Anonymous and permanent users can view the news feed"
: ポリシーの名前です。 -
on news_feed
: ポリシーが適用されるテーブルを指定します。 -
as restrictive
: ポリシーの動作を定義します。 この場合、指定されたすべての条件を満たすユーザーだけがアクセスを許可されます。 -
for insert
andfor select
: ポリシーが適用される操作の種類を指定します (挿入と選択)。 -
to authenticated
: アクセスを認証済みユーザーに制限します。 -
with check ((select (auth.jwt()->>'is_anonymous')::boolean) is false )
: 最初のポリシーの追加チェック。 認証済みユーザーで、かつ匿名ユーザーではない (正規ユーザー) のみ投稿を許可します。 -
using (true)
: 2 番目のポリシーの一部。 常に true を返すため、認証済みユーザーであれば誰でも閲覧を許可します。
補足:
- このコードは、データベース内で JWT クレームにアクセスできる拡張機能またはメカニズム (例:
auth.jwt()
関数) が存在することを前提としています。 - 匿名ユーザーのクレーム名として "is_anonymous" 以外を使用する方が、よりわかりやすい場合があります。
このコード例は、ニュースフィードへのアクセスを制御する基本的な方法を示しています。 具体的な要件に応じて、さらに複雑なポリシーを作成することができます。
IDの衝突の解決
アプリケーションの要件によっては、匿名ユーザーを正規ユーザーに変換する際にデータの競合が発生する可能性があります。
たとえば電子商取引アプリケーションの場合、匿名ユーザーはサインアップ/サインインせずに ショッピングカートに商品を追加することができます。彼らが既存のアカウントにサインインすることを決定したとき、ショッピングカートのデータの競合をどのように解決したいかを決定する必要があります。
- 1.カート内の商品を既存のアカウント内の商品で上書きする。
- カート内の商品を匿名ユーザーの商品で上書きする。
- カート内のアイテムをマージする
ショッピングカートでの匿名ユーザーと登録ユーザーのデータの整合について説明します。
-
問題
- お店サイトで、ログインせず商品をカートに入れる (匿名ユーザー)
- 後で会員登録 (既存アカウント) またはログイン (既存アカウント) すると、カートの中身はどうなる?
-
解決方法
-
主に3つの方法があります。
- 既存アカウントの上書き: ログインした際のカート情報で、匿名カートの中身を消します。
- 匿名カートの上書き: ログインした際の、保存されているカート情報で、匿名カートの中身を消します。
- カートの中身をマージ (合体): 匿名カートと、既存アカウントのカートにある商品を両方とも残します。
-
-
どれを選ぶべきか?
- お客様がカートに入れた匿名商品も残したいなら、マージ (合体) がおすすめです。
- 既存アカウントのカート情報が優先なら、1 (既存アカウントの上書き) または 2 (匿名カートの上書き) を選べばOKです。
不正行為の防止とレート制限
はじめに
匿名ユーザーはデータベースに保存されるため、悪意のあるユーザーがエンドポイントを悪用し、データベースのサイズを極端に増加させる可能性があります。
不正行為の防止策
この問題を防ぐために、以下の対策を講じることが推奨されます。
-
不可視 Captcha または Cloudflare Turnstile: https://supabase.com/docs/guides/auth/auth-captcha の有効化:
これは、匿名サインインの悪用を阻止する効果的な方法です。- 有効化は ダッシュボード: https://supabase.com/dashboard/project/_/auth/rate-limits から行えます。
-
IP ベースのレート制限:
- 1 時間あたり 30 リクエストに制限を設定することで、悪意のあるユーザーによるリクエストの過剰送信を抑制できます。
- 制限値は ダッシュボード: https://supabase.com/dashboard/project/_/auth/rate-limits から変更可能です。
レート制限の詳細
レート制限の詳細については、以下のドキュメントを参照してください。
- レート制限 - リソース割り当てと不正行為防止: https://supabase.com/docs/guides/platform/going-into-prod#rate-limiting-resource-allocation--abuse-prevention
その他
上記に加え、以下の点にも注意が必要です。
- データベースのサイズとパフォーマンスを定期的に監視し、異常がないか確認する。
- 不審なアクティビティを発見したら、速やかに調査を行う。
自動クリーンアップ
現在、Supabaseでは匿名ユーザーの自動クリーンアップ機能は提供されていません。
手動での削除
しかし、以下のSQLクエリを実行することで、プロジェクトから匿名ユーザーを削除することができます。
-- 30日以上前に作成された匿名ユーザーを削除
delete from auth.users
where is_anonymous is true and created_at < now() - interval '30 days';
注意事項
- 上記のクエリは、30日以上前に作成された匿名ユーザーのみを削除します。
- 削除対象となるユーザーの絞り込み条件は、
created_at
カラム以外にも変更可能です。 - データベースを操作する前に、必ずバックアップを取ることを推奨します。
代替手段
自動クリーンアップ機能が利用できない場合は、以下の代替手段を検討することができます。
- 定期的な手動削除: 上記のSQLクエリを定期的に実行することで、不要な匿名ユーザーを削除することができます。
- ユーザーアクティビティに基づく削除: 一定期間アクティビティがない匿名ユーザーを自動的に削除する仕組みを構築することができます。
- サードパーティ製ツール: Supabaseと連携して匿名ユーザーを管理できるサードパーティ製ツールを利用することができます。