Skip to content
Auth

Firebase Auth

Use Firebase Auth with your Supabase project

Firebase Auth 可以和 Supabase Auth 一起作为第三方认证提供,也可以单独在你的 Supabase 项目中使用。

🌐 Firebase Auth can be used as a third-party authentication provider alongside Supabase Auth, or standalone, with your Supabase project.

入门 #

🌐 Getting started

  1. 首先,你需要添加一个集成,将你的 Supabase 项目与 Firebase 项目连接起来。你需要在 Firebase 控制台 获取项目 ID。
  2. 在你项目的身份验证设置中添加一个新的第三方认证集成。
  3. 如果你在自托管时使用第三方认证,记得为你 public schema、Storage 和 Realtime 中的所有表创建并附加限制性 RLS 策略,以防止来自无关 Firebase 项目的未授权访问
  4. role: 'authenticated' 自定义用户声明 分配给你所有的用户。
  5. 终于在你的应用里设置好了 Supabase 客户端。

设置 Supabase 客户端库 #

🌐 Setup the Supabase client library

为 Web 创建客户端就像传递 accessToken 异步函数一样简单。这个函数应当返回当前用户的 Firebase Auth JWT(如果没有找到这样的用户则返回 null)。

🌐 Creating a client for the Web is as easy as passing the accessToken async function. This function should return the Firebase Auth JWT of the current user (or null if no such user) is found.

1
import { createClient } from '@supabase/supabase-js'
2
3
const supabase = createClient(
4
'https://<supabase-project>.supabase.co',
5
'SUPABASE_PUBLISHABLE_KEY',
6
{
7
accessToken: async () => {
8
return (await firebase.auth().currentUser?.getIdToken(/* forceRefresh */ false)) ?? null
9
},
10
}
11
)

确保你应用中的所有用户都设置了 role: 'authenticated' 自定义声明。如果你使用 onCreate 云函数为新注册的用户添加这个自定义声明,那么在注册后你需要立即调用 getIdToken(/* forceRefresh */ true),因为 onCreate 函数不会同步运行。

🌐 Make sure all users in your application have the role: 'authenticated' custom claim set. If you're using the onCreate Cloud Function to add this custom claim to newly signed up users, you will need to call getIdToken(/* forceRefresh */ true) immediately after sign up as the onCreate function does not run synchronously.

在你的项目中添加一个新的第三方认证集成 #

🌐 Add a new Third-Party Auth integration to your project

在仪表板中,进入你项目的 身份验证设置,找到第三方认证部分,添加一个新的集成。

🌐 In the dashboard navigate to your project's Authentication settings and find the Third-Party Auth section to add a new integration.

在命令行接口中,将以下配置添加到你的 supabase/config.toml 文件:

🌐 In the CLI add the following config to your supabase/config.toml file:

1
[auth.third_party.firebase]
2
enabled = true
3
project_id = "<id>"

为你项目的 RLS 策略增加一层额外的安全保护(仅自托管) #

🌐 Adding an extra layer of security to your project's RLS policies (self-hosting only)

Firebase Auth 对所有项目使用同一套 JWT 签名密钥。这意味着来自与你无关的 Firebase 项目的 JWT 可能会访问你 Supabase 项目中的数据。

🌐 Firebase Auth uses a single set of JWT signing keys for all projects. This means that JWTs issued from an unrelated Firebase project to yours could access data in your Supabase project.

当使用 Supabase 托管平台时,来自你未注册的 Firebase 项目 ID 的 JWT 在到达你的数据库之前就会被拒绝。如果是自我托管,实现这个机制就是你的责任。一种简单的防护方法是为 public 架构中的所有表 创建并维护以下 RLS 策略。你还应该将这个策略附加到 Storage 桶或 Realtime 通道上。

🌐 When using the Supabase hosted platform, JWTs coming from Firebase project IDs you have not registered will be rejected before they reach your database. When self-hosting implementing this mechanism is your responsibility. An easy way to guard against this is to create and maintain the following RLS policies for all of your tables in the public schema. You should also attach this policy to Storage buckets or Realtime channels.

建议你使用严格的 Postgres 行级安全策略

🌐 It's recommended you use a restrictive Postgres Row-Level Security policy.

受限的 RLS 策略与普通(或宽松)策略的不同之处在于,它们在定义时使用 as restrictive 子句。它们不是授予权限,而是限制任何现有或未来的权限。这在像这种情况下非常有用,因为 Firebase Auth 的技术限制依然和你的应用逻辑分开。

🌐 Restrictive RLS policies differ from regular (or permissive) policies in that they use the as restrictive clause when being defined. They do not grant permissions, but rather restrict any existing or future permissions. They're great for cases like this where the technical limitations of Firebase Auth remain separate from your app's logic.

这是这样一个 RLS 策略的例子,它将只限制访问你项目的用户(用 <firebase-project-id> 表示),而不是其他任何 Firebase 项目的用户。

🌐 This is an example of such an RLS policy that will restrict access to only your project's (denoted with <firebase-project-id>) users, and not any other Firebase project.

1
create policy "Restrict access to Supabase Auth and Firebase Auth for project ID <firebase-project-id>"
2
on table_name
3
as restrictive
4
to authenticated
5
using (
6
(auth.jwt()->>'iss' = 'https://<project-ref>.supabase.co/auth/v1')
7
or
8
(
9
auth.jwt()->>'iss' = 'https://securetoken.google.com/<firebase-project-id>'
10
and
11
auth.jwt()->>'aud' = '<firebase-project-id>'
12
)
13
);

如果你的应用中有很多表,或者需要管理针对存储实时的复杂RLS策略,定义一个稳定的Postgres函数来执行检查,可以帮助减少重复代码。例如:

🌐 If you have a lot of tables in your app, or need to manage complex RLS policies for Storage or Realtime it can be useful to define a stable Postgres function that performs the check to cut down on duplicate code. For example:

1
create function public.is_supabase_or_firebase_project_jwt()
2
returns bool
3
language sql
4
stable
5
returns null on null input
6
return (
7
(auth.jwt()->>'iss' = 'https://<project-ref>.supabase.co/auth/v1')
8
or
9
(
10
auth.jwt()->>'iss' = concat('https://securetoken.google.com/<firebase-project-id>')
11
and
12
auth.jwt()->>'aud' = '<firebase-project-id>'
13
)
14
);

确保你用你的 Supabase 项目 ID 替换 <project-ref>,用你的 Firebase 项目 ID 替换 <firebase-project-id>。然后你所有表、存储桶和通道的限制策略可以简化为:

🌐 Make sure you substitute <project-ref> with your Supabase project's ID and the <firebase-project-id> to your Firebase Project ID. Then the restrictive policies on all your tables, buckets and channels can be simplified to be:

1
create policy "Restrict access to correct Supabase and Firebase projects"
2
on table_name
3
as restrictive
4
to authenticated
5
using ((select public.is_supabase_or_firebase_project_jwt()) is true);

分配“角色”自定义声明 #

🌐 Assign the "role" custom claim

你的 Supabase 项目会检查所有发送给它的 JWT 中的 role 声明,以便在使用 Data API、Storage 或 Realtime 授权时分配正确的 Postgres 角色。

🌐 Your Supabase project inspects the role claim present in all JWTs sent to it, to assign the correct Postgres role when using the Data API, Storage or Realtime authorization.

默认情况下,Firebase JWT 中不包含 role 声明。如果你把这样的 JWT 发送到你的 Supabase 项目,在执行 Postgres 查询时会分配 anon 角色。你应用的大部分逻辑将可以通过 authenticated 角色访问。

🌐 By default, Firebase JWTs do not contain a role claim in them. If you were to send such a JWT to your Supabase project, the anon role would be assigned when executing the Postgres query. Most of your app's logic will be accessible by the authenticated role.

使用 Firebase 身份验证功能来分配已验证的角色 #

🌐 Use Firebase Authentication functions to assign the authenticated role

根据你的 Firebase 项目配置,你有两种选择来设置 Firebase 身份验证功能:

🌐 You have two choices to set up a Firebase Authentication function depending on your Firebase project's configuration:

  1. 最简单的方法:使用阻止式Firebase认证功能,但这只有在你的项目使用带身份平台的Firebase认证时才可用。
  2. 使用 admin SDK 手动为所有用户分配自定义权限,并定义一个 onCreate Firebase 身份验证云函数 来将角色保存到所有新创建的用户。
1
import { beforeUserCreated, beforeUserSignedIn } from 'firebase-functions/v2/identity'
2
3
export const beforecreated = beforeUserCreated((event) => {
4
return {
5
customClaims: {
6
// The Supabase project will use this role to assign the `authenticated`
7
// Postgres role.
8
role: 'authenticated',
9
},
10
}
11
})
12
13
export const beforesignedin = beforeUserSignedIn((event) => {
14
return {
15
customClaims: {
16
// The Supabase project will use this role to assign the `authenticated`
17
// Postgres role.
18
role: 'authenticated',
19
},
20
}
21
})

注意,你可以不用 customClaims,而是使用 sessionClaims。不同之处在于,session_claims 不会保存在 Firebase 用户资料中,但只要用户登录就仍然有效。

🌐 Note that instead of using customClaims you can instead use sessionClaims. The difference is that session_claims are not saved in the Firebase user profile, but remain valid for as long as the user is signed in.

最后部署你的函数,让更改生效:

🌐 Finally deploy your functions for the changes to take effect:

1
firebase deploy --only functions

请注意,这些函数只会在新用户注册和登录时调用。现有用户的 ID 令牌中不会包含这些声明。你需要使用管理员 SDK 为所有用户分配角色自定义声明。确保在部署了上面描述的阻塞 Firebase 身份验证函数之后再执行此操作。

🌐 Note that these functions are only called on new sign-ups and sign-ins. Existing users will not have these claims in their ID tokens. You will need to use the admin SDK to assign the role custom claim to all users. Make sure you do this after the blocking Firebase Authentication functions as described above are deployed.

使用管理员 SDK 给所有用户分配自定义角色声明 #

🌐 Use the admin SDK to assign the role custom claim to all users

你需要运行一个脚本,为你所有现有的 Firebase Authentication 用户分配 role: 'authenticated' 自定义声明。你可以通过结合 列出用户设置自定义用户声明 管理 API 来实现。下面提供了一个示例脚本:

🌐 You need to run a script that will assign the role: 'authenticated' custom claim to all of your existing Firebase Authentication users. You can do this by combining the list users and set custom user claims admin APIs. An example script is provided below:

1
'use strict';
2
const { initializeApp } = require('firebase-admin/app');
3
const { getAuth } = require('firebase-admin/auth');
4
initializeApp();
5
6
async function setRoleCustomClaim() {
7
let nextPageToken = undefined
8
9
do {
10
const listUsersResult = await getAuth().listUsers(1000, nextPageToken)
11
12
nextPageToken = listUsersResult.pageToken
13
14
await Promise.all(listUsersResult.users.map(async (userRecord) => {
15
try {
16
await getAuth().setCustomUserClaims(userRecord.id, {
17
role: 'authenticated'
18
})
19
} catch (error) {
20
console.error('Failed to set custom role for user', userRecord.id)
21
}
22
})
23
} while (nextPageToken);
24
};
25
26
setRoleCustomClaim().then(() => process.exit(0))

在所有用户都收到 role: 'authenticated' 声明后,它将出现在用户所有新发放的 ID 令牌中。

🌐 After all users have received the role: 'authenticated' claim, it will appear in all newly issued ID tokens for the user.