新的 API 密钥和非对称认证
Configure new API keys and ES256 asymmetric authentication for self-hosted Supabase.
你可以配置自托管的 Supabase,同时使用 可发布和私密的 API 密钥 以及传统的 API 密钥(ANON_KEY 和 SERVICE_ROLE_KEY HS256 签名的 JWT)。
🌐 You can configure self-hosted Supabase to use the publishable and secret API keys alongside the legacy API keys (ANON_KEY and SERVICE_ROLE_KEY HS256-signed JWTs).
在你开始之前 #
🌐 Before you begin
- 完成 Docker 设置指南,确保在你的
.env文件中设置了JWT_SECRET、ANON_KEY和SERVICE_ROLE_KEY。快速开始(Linux) 会自动处理这些;手动操作则运行generate-keys.sh。 - 如果你正在从传统的自托管 Supabase 环境升级,记得查看 更新日志 并 添加/更新 以下文件:
.env.example(将新部分合并到你的.env文件中)docker-compose.ymlutils/add-new-auth-keys.shutils/rotate-new-api-keys.shvolumes/api/envoy/*
添加新密钥 #
🌐 Adding the new keys
在你的项目目录里,你有 docker-compose.yml:
🌐 From your project directory where you have docker-compose.yml:
sh utils/add-new-auth-keys.sh --update-env这会生成新的配置环境变量并将它们写入 .env。省略 --update-env 可以以交互方式查看并确认更改。
🌐 This generates new configuration environment variables and writes them to .env. Omit --update-env to review and confirm the changes interactively.
这个脚本从 .env 读取 JWT_SECRET,并把它作为对称密钥包含在 JWT_KEYS 和 JWT_JWKS 中。如果你之后更改了 JWT_SECRET,你也必须重新生成 JWKS。
🌐 The script reads JWT_SECRET from .env and includes it as a symmetric key inside both JWT_KEYS and JWT_JWKS. If you later change JWT_SECRET, you must regenerate the JWKS as well.
此外,为了让新的身份验证正常工作,脚本会自动取消注释以下配置:
🌐 In addition, the following configuration is uncommented automatically by the script for the new authentication to work correctly:
auth: environment: # JSON array of signing JWKs (EC private + legacy symmetric) GOTRUE_JWT_KEYS: ${JWT_KEYS:-[]}rest: environment: # PostgREST accepts a plain-text symmetric secret, a single JWK, or a JWKS. PGRST_JWT_SECRET: ${JWT_JWKS:-${JWT_SECRET}}realtime: environment: # JWKS for token verification (EC public + legacy symmetric) API_JWT_JWKS: ${JWT_JWKS:-{"keys":[]}}storage: environment: # JWKS for token verification (EC public + legacy symmetric) JWT_JWKS: ${JWT_JWKS:-{"keys":[]}}functions: environment: # JWKS for token verification (EC public + legacy symmetric). SUPABASE_JWKS: ${JWT_JWKS:-{"keys":[]}}嵌套变量插值(${A:-${B}})需要 podman-compose >= 1.6.0。早期版本(一些 Linux 发行版仍然提供)不支持它——如果你使用的是较旧的 podman-compose,要么升级,要么将每个嵌套表达式直接替换成所需的变量,具体替换方式请参见 docker-compose.yml 中的内联注释。
🌐 Nested variable interpolation (${A:-${B}}) requires podman-compose >= 1.6.0. Earlier versions (still shipped by some Linux distributions) do not support it - if you are on an older podman-compose, either upgrade or replace each nested expression with the required variable directly, see the inline comments in docker-compose.yml for the exact substitutions.
重启所有服务:
🌐 Restart all services:
sh run.sh recreate新的 API 密钥格式 #
🌐 New API keys format
这些密钥使用与 Supabase 平台上的 API 密钥 相同的格式:
🌐 These keys use the same format as API keys on the Supabase platform:
sb_publishable_<22-char-random>_<8-char-checksum>sb_secret_<22-char-random>_<8-char-checksum>正在检查设置 #
🌐 Verifying the setup
使用新的密钥测试:
🌐 Test with the new secret key:
curl http://<your-domain>/rest/v1/ \-H "apikey: your-supabase-secret-key"你应该会收到来自 PostgREST 的有效响应。然后确认旧版服务角色密钥仍然可用:
🌐 You should receive a valid response from PostgREST. Then verify that the legacy service role key still works:
curl http://<your-domain>/rest/v1/ \-H "apikey: your-service-role-key"两者都应该可以,并返回相同的结果。
🌐 Both should work and return the same result.
/rest/v1/ 是开放 API 根,需要管理员级别的密钥(sb_secret_* 或旧版 SERVICE_ROLE_KEY)。公共密钥(sb_publishable_* 或旧版 ANON_KEY)在这个端点会返回 403。
你也可以验证公共 JWKS 端点:
🌐 You can also verify the public JWKS endpoint:
curl http://<your-domain>/auth/v1/.well-known/jwks.json这应该返回 EC 公钥(对称密钥被排除在外)。第三方服务可以使用这个接口获取公钥,并在不需要私钥的情况下验证非对称用户会话的 JWT。
🌐 This should return the EC public key (the symmetric key is excluded). Third-party services can use this endpoint to obtain the public key and verify asymmetric user session JWTs without needing the private key.
环境变量配置 #
🌐 Environment variables configuration
在 .env.example 中,新变量默认是空值。当为空时,API 网关和所有服务会以仅传统模式运行:sb_publishable 和 sb_secret 的 API 密钥未配置。
🌐 New variables default to empty values in .env.example. When empty, the API gateway and all services operate in legacy-only mode: sb_publishable and sb_secret API keys are not configured.
| 环境变量(已有和新建) | 类型 | 描述 |
|---|---|---|
JWT_SECRET | 对称密钥 | 现有: 用于签署和验证 HS256 JWT 的共享密钥。被多个服务使用。 |
ANON_KEY | HS256 JWT | 现有: 旧版客户端 API 密钥。嵌入了带 role: "anon" 的 JWT。 |
SERVICE_ROLE_KEY | HS256 JWT | 现有: 旧版服务器端 API 密钥。嵌入的 JWT,带有 role: "service_role"。 |
SUPABASE_PUBLISHABLE_KEY | 不透明 | 新: 带校验和的短随密钥钥。用于客户端,替代 ANON_KEY。 |
SUPABASE_SECRET_KEY | 不透明 | 新: 带校验和的短随密钥钥。用于服务器端,替代 SERVICE_ROLE_KEY。 |
JWT_KEYS | JSON 数组 | 新: 包含新的非对称密钥对和旧对称密钥的签名 JWK JSON 数组。Auth 用它来签署令牌。 |
JWT_JWKS | JWKS(JSON) | 新: 包含新的公钥和旧的对称密钥。用于 PostgREST、Realtime、Storage 和 Functions。 |
与 Supabase 平台的不同 #
🌐 Differences from the Supabase platform
- 每个角色一个密钥。 自托管的 Supabase 支持单个
sb_publishable和单个sb_secret。该平台允许每个项目创建多个sb_密钥。 - 不进行校验和验证。 不透明密钥使用与平台相同的格式(
sb_publishable_<random>_<checksum>),但是 API 网关不会验证校验和。API 网关会将密钥作为不透明字符串进行匹配。
向后兼容 #
🌐 Backward compatibility
新的认证配置完全向后兼容:
🌐 The new authentication configuration is fully backward compatible:
- **API网关同时接受两种密钥类型。**你可以逐步迁移客户端——有些使用老的API密钥,有些使用新的。
- JWKS 包含对称密钥。
JWT_JWKS同时包含 EC 公钥(用于验证新的 ES256 令牌)以及旧的JWT_SECRET作为对称 JWK(用于验证旧的 HS256 令牌)。接收到JWT_JWKS的服务可以验证这两种类型的令牌。 - 不需要更改数据库。 非对称密钥系统完全在 API 网关和服务配置层运行。
当设置 JWT_KEYS 时,Auth 会开始使用新的非对称 ES256 密钥对签署新的用户会话 JWT。确保所有验证令牌的服务(PostgREST、Realtime、Storage)都配置了 JWT_JWKS,这样它们就可以验证新的 ES256 和旧的 HS256 令牌。
🌐 When JWT_KEYS is set, Auth will start signing new user session JWTs with the new asymmetric ES256 key pair. Make sure all services that verify tokens (PostgREST, Realtime, Storage) are configured with JWT_JWKS so they can verify both the new ES256 and legacy HS256 tokens.
轮换新的 API 密钥 #
🌐 Rotating the new API keys
如果你的新 API 密钥被泄露,或者你想定期更换它们,你可以在不动非对称密钥对的情况下重新生成 sb_publishable 和 sb_secret:
🌐 If your new API keys are compromised or you want to rotate them periodically, you can regenerate sb_publishable and sb_secret without touching the asymmetric key pair:
sh utils/rotate-new-api-keys.sh --update-env更换密钥后,重启服务并用新密钥更新你的客户端应用:
🌐 After rotating, restart services and update your client applications with the new keys:
sh run.sh recreate轮换新的 API 密钥不会使现有的用户会话失效。Auth 发放的用户会话 JWT 不受影响,因为它们是使用非对称密钥对进行验证的,而这个密钥对保持不变。
🌐 Rotating new API keys does not invalidate existing user sessions. User session JWTs issued by Auth are unaffected because they are verified using the asymmetric key pair, which remains unchanged.
正在重新生成非对称密钥对 #
🌐 Regenerating asymmetric key pair
如果 EC 私钥被泄露或你需要重新生成所有东西:
🌐 If the EC private key is compromised or you need to regenerate everything:
sh utils/add-new-auth-keys.sh --update-env这会生成一个新的 EC P-256 密钥对、新的 JWKS、新的非对称 JWT,以及新的 sb_ API 密钥。更新 .env 并重启服务后:
🌐 This generates a new EC P-256 key pair, new JWKS, new asymmetric JWTs, and new sb_ API keys. After updating .env and restarting services:
- 新用户会话令牌将使用新的EC密钥进行签名。
- 使用旧 EC 密钥签署的现有用户会话令牌将验证失败。用户需要重新登录。
- 用旧的对称密钥(
JWT_SECRET)签署的现有用户会话令牌仍然可以使用,因为JWT_SECRET没有改变,并且仍然包括在新的 JWKS 中。
重新生成非对称密钥会使所有 ES256 用户会话失效。如果你的用户有活跃会话,请安排一个维护时间。
🌐 Regenerating asymmetric keys invalidates all ES256 user sessions. Plan a maintenance window if your users have active sessions.
它是怎么运作的 #
🌐 How it works
通过 supabase-js 的请求,每个服务都会包含两个头信息,Edge Functions 除外:
🌐 Requests via supabase-js include two headers for every service except Edge Functions:
apikey- API 密钥(sb_或旧版 JWT)Authorization- 未认证时,客户端 SDK 会把 API 密钥复制到这里(Bearer sb_publishable_xxx或Bearer eyJ...)。认证后,这里会包含由 Auth 生成的用户会话 JWT。
对于 实时 WebSocket 连接,API 密钥作为 ?apikey= 查询参数发送在升级 URL 中,而不是使用 apikey 头。
🌐 For Realtime WebSocket connections, the API key is sent as a ?apikey= query parameter in the upgrade URL instead of an apikey header.
存储 和 边缘函数 也可以接受没有 API 密钥的请求。这些服务会自己处理身份验证。
有关 API 网关如何路由和验证请求的详细信息,请参阅 Envoy API 网关指南。
🌐 For details on how the API gateway routes and authenticates requests, see the Envoy API Gateway guide.
额外资源 #
🌐 Additional resources
- API 密钥 - Supabase 平台上的 API 密钥如何工作
- 认证架构 - 认证服务如何处理身份验证和令牌签发
- JWT 签名密钥 - 关于管理 Supabase Auth 用于创建和验证 JSON Web 令牌的密钥的最佳实践
- JSON Web Token (JWT) - 如何在 Supabase 中最佳使用 JSON Web Token
- 使用 Docker 自托管 - 初始设置指南,包括旧密钥生成
在 GitHub 上:
🌐 On GitHub: