Skip to content
Auth

JSON 网页令牌 (JWT)

Information on how best to use JSON Web Tokens with Supabase

一个 JSON Web Token 是一种数据结构,以字符串形式表示,通常包含关于用户的身份和授权信息。它会编码关于其有效期的信息,并使用加密密钥进行签名,以防止被篡改。

🌐 A JSON Web Token is a type of data structure, represented as a string, that usually contains identity and authorization information about a user. It encodes information about its lifetime and is signed with a cryptographic key to make it tamper-resistant.

Supabase Auth 会在用户保持登录状态的整个期间,为每个用户会话不断发放新的 JWT。查看关于 会话 的完整指南,了解如何根据你的需求定制这个过程。

🌐 Supabase Auth continuously issues a new JWT for each user session, for as long as the user remains signed in. Check the comprehensive guide on Sessions to find out how you can tailor this process for your needs.

JWT 为行级安全提供了基础。每个 Supabase 产品都能够在使用 Postgres 策略和角色授权访问项目数据之前,安全地解码并验证它收到的 JWT 的有效性。

🌐 JWTs provide the foundation for Row Level Security. Each Supabase product is able to securely decode and verify the validity of a JWT it receives before using Postgres policies and roles to authorize access to the project's data.

Supabase 提供了一个全面的系统来管理用来创建和验证 JSON Web 令牌的 JWT 签名密钥

🌐 Supabase provides a comprehensive system of managing JWT Signing Keys used to create and verify JSON Web Tokens.

介绍 #

🌐 Introduction

JWT 是具有以下结构的字符串:

🌐 JWTs are strings that have the following structure:

1
<header>.<payload>.<signature>

每一部分都是一个经过 Base64-URL 编码的 JSON 字符串,或者用于签名的字节。

🌐 Each part is a string of Base64-URL encoded JSON, or bytes for the signature.

标题

1
{
2
"typ": "JWT",
3
"alg": "<HS256 | ES256 | RS256>",
4
"kid": "<unique key identifier>"
5
}

提供一些关于字符串的基本识别信息,说明它的类型 typ、可以用来验证数据的加密算法 alg,以及可选的在验证时应使用的唯一密钥标识。

🌐 Gives some basic identifying information about the string, indicating its type typ, the cryptographic algorithm alg that can be used to verify the data, and optionally the unique key identifier that should be used when verifying it.

有效载荷

1
{
2
"iss": "https://project_id.supabase.co/auth/v1",
3
"exp": 12345678,
4
"sub": "<user ID>",
5
"role": "authenticated",
6
"email": "someone@example.com",
7
"phone": "+15552368"
8
// ...
9
}

提供关于用户(或由令牌表示的其他实体)的标识信息(称为“声明”)。通常,JWT传递的信息可能是用户能访问的内容(称为访问令牌)或用户身份(称为ID令牌)。你可以使用自定义访问令牌钩子来添加、删除或更改令牌中的声明。有几个声明是很重要的:

🌐 Provides identifying information (called "claims") about the user (or other entity) that is represented by the token. Usually a JWT conveys information about what the user can access (then called Access Token) or who the user is (then called ID Token). You can use a Custom Access Token Hook to add, remove or change claims present in the token. A few claims are important:

声明描述
iss标识发布令牌的服务器。如果你在这个 URL 后面加上 /.well-known/jwks.json,你就可以获取用于验证令牌的公钥。
exp设置一个时间限制,超过这个时间即使令牌签名正确也不再可信,会被视为过期。
sub意思是 主题,是令牌所代表用户的唯一 ID。
role在应用行级安全策略时使用的 Postgres 角色。
...其他所有声明都可以快速访问个人信息,而无需查询数据库或向认证服务器发送请求。

签名

使用共享密钥公钥加密数字签名。签名的目的是在不依赖数据库访问、Auth 服务器的活跃状态或性能的情况下验证 <header>.<payload> 字符串的真实性。验证签名时,避免自己实现算法,而是依赖 supabase.auth.getClaims() 或你所用语言的其他高质量 JWT 验证库。

🌐 A digital signature using a shared secret or public-key cryptography. The purpose of the signature is to verify the authenticity of the <header>.<payload> string without relying on database access, liveness or performance of the Auth server. To verify the signature avoid implementing the algorithms yourself and instead rely on supabase.auth.getClaims(), or other high-quality JWT verification libraries for your language.

Supabase 和 JWT #

🌐 Supabase and JWTs

Supabase 会在这些情况下为你创建 JWT:

🌐 Supabase creates JWTs in these cases for you:

  1. 在使用 Supabase Auth 时,每个用户在保持登录状态时都会生成一个访问令牌(JWT)。这些令牌有效期很短,所以随着用户与 Supabase API 的交互,它们会不断被重新发放。
  2. 在使用可发布或秘密 API 密钥时即时处理。每个 API 密钥都会被转换成一个短期有效的 JWT,然后用它来授权访问你的数据。通常无法直接获取这些短期令牌。

除了创建 JWT,Supabase 还可以通过 第三方认证 功能接受来自其他认证服务器的 JWT,或者接受通过导入的 JWT 签名密钥 在外部生成的 JWT。

🌐 In addition to creating JWTs, Supabase can also accept JWTs from other authentication servers via the Third-Party Auth feature or ones that have been minted externally via an imported JWT Signing Key.

使用自定义或第三方 JWT #

🌐 Using custom or third-party JWTs

你的 Supabase 项目在 Authorization: Bearer <jwt> 头中接受 JWT。如果你使用 Supabase 客户端库,它会为你处理这个。

🌐 Your Supabase project accepts a JWT in the Authorization: Bearer <jwt> header. If you're using the Supabase client library, it does this for you.

如果你已经在使用 Supabase Auth,当用户登录时,他们的访问令牌 JWT 会自动管理,并在每次 API 调用时为你发送。

🌐 If you are already using Supabase Auth, when a user is signed in, their access token JWT is automatically managed and sent for you with every API call.

如果你想从第三方认证提供商发送 JWT,或者使用你导入的 JWT 签名密钥自己生成的 JWT,你可以通过 accessToken 选项传递给客户端库。

🌐 If you wish to send a JWT from a Third-Party Auth provider, or one you made yourself by using a JWT signing key you imported, you can pass it to the client library using the accessToken option.

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 '<your JWT here>'
9
},
10
}
11
)

过去有人建议在 Supabase 客户端上设置自定义头部,用 Authorization 头部包含你的自定义 JWT。但现在不推荐这样做了,因为这种方式灵活性较差,而且当与 Supabase Auth 的用户会话结合使用时容易引起混淆。

🌐 In the past there was a recommendation to set custom headers on the Supabase client with the Authorization header including your custom JWT. This is no longer recommended as it's less flexible and causes confusion when combined with a user session from Supabase Auth.

验证来自 Supabase 的 JWT #

🌐 Verifying a JWT from Supabase

如果你无法使用 Supabase 客户端库,下面的方法可以帮助你安全地验证由 Supabase 发出的 JWT。

🌐 If you're not able to use the Supabase client libraries, the following can be used to help you securely verify JWTs issued by Supabase.

Supabase Auth 为每个 Supabase 项目提供一个 JSON Web Key 集合 URL:

🌐 Supabase Auth exposes a JSON Web Key Set URL for each Supabase project:

1
GET https://project-id.supabase.co/auth/v1/.well-known/jwks.json

它会返回一个 JWKS 对象,其中包含一个或多个非对称的 JWT 签名密钥(仅包括它们的公钥)。请注意,如果你没有使用非对称的 JWT 签名密钥,这个端点是不会返回任何密钥的。

🌐 Which responds with JWKS object containing one or more asymmetric JWT signing keys (only their public keys). Be aware that this endpoint does not return any keys if you are not using asymmetric JWT signing keys.

1
{
2
"keys": [
3
{
4
"kid": "<match with kid from JWT header>",
5
"alg": "<match with alg from JWT header>",
6
"kty": "<RSA|EC|OKP>",
7
"key_ops": ["verify"]
8
// public key fields
9
}
10
]
11
}

这个端点是直接从认证服务器提供的,但也会被 Supabase Edge 额外缓存 10 分钟,无论你在哪里进行验证,都能显著加快访问速度。注意缓存过期时间很重要,以免不小心拒绝了有效的用户访问令牌。我们建议在创建备用签名密钥或撤销之前使用过的密钥时,至少等待 20 分钟。

🌐 This endpoint is served directly from the Auth server, but is also additionally cached by the Supabase Edge for 10 minutes, significantly speeding up access to this data regardless of where you're performing the verification. It's important to be aware of the cache expiry time to prevent unintentionally rejecting valid user access tokens. We recommend waiting at least 20 minutes when creating a standby signing key, or revoking a previously used key.

确保你的应用不要长时间缓存这些数据,因为这可能会让撤销变得困难。如果你确实缓存了,确保在更换签名密钥时提供一种清理缓存的方法,以避免无意中拒绝有效的用户访问令牌。

🌐 Make sure that you do not cache this data for longer in your application, as it might make revocation difficult. If you do, make sure to provide a way to purge this cache when rotating signing keys to avoid unintentionally rejecting valid user access tokens.

下面是一个如何使用 jose TypeScript JWT 验证库 来处理 Supabase JWT 的示例:

🌐 Below is an example of how to use the jose TypeScript JWT verification library with Supabase JWTs:

1
import { createRemoteJWKSet, jwtVerify } from 'jose'
2
3
const PROJECT_JWKS = createRemoteJWKSet(
4
new URL('https://project-id.supabase.co/auth/v1/.well-known/jwks.json')
5
)
6
7
/**
8
* Verifies the provided JWT against the project's JSON Web Key Set.
9
*/
10
async function verifyProjectJWT(jwt: string) {
11
return jwtVerify(jwt, PROJECT_JWKS)
12
}

使用共享的秘密签名密钥进行验证 #

🌐 Verifying with a shared secret signing key

如果你的项目使用共享密钥(HS256)签名密钥,我们建议始终通过向认证服务器发送类似这样的请求来直接验证用户访问令牌:

🌐 If your project is using a shared secret (HS256) signing key, we recommend always verifying a user access token directly with the Auth server by sending a request like so:

1
GET https://project-id.supabase.co/auth/v1/user
2
apikey: publishable key
3
Authorization: Bearer <JWT>

如果服务器返回 HTTP 200 OK,那么 JWT 是有效的,否则就无效。

🌐 If the server responds with HTTP 200 OK, the JWT is valid, otherwise it is not.

因为认证服务器只在你项目指定的区域运行,并没有全球分布,所以根据你执行检查的地点,这个检查可能会很慢。尽量不要从运行在边缘的服务器或函数上做这种检查,最好是路由到与你项目在同一区域的服务器。

🌐 Because the Auth server runs only in your project's specified region and is not globally distributed, doing this check can be quite slow depending on where you're performing the check. Avoid doing checks like this from servers or functions running on the edge, and prefer routing to a server within the same geographical region as your project.

如果你使用共享密钥(HS256)作为签名密钥,你可能想用共享密钥来验证。我们强烈不推荐这种做法。

🌐 If you are using a shared secret (HS256) signing key, you may wish to verify using the shared secret. We strongly recommend against this approach.

查看你的语言的 JWT 验证库,了解如何安全地验证使用共享密钥(HS256)签名的 JWT。我们强烈建议按照上面描述的方法依赖认证服务器,或者改用基于公钥加密(RSA、椭圆曲线)的不同签名密钥。

🌐 Check the JWT verification libraries for your language on how to securely verify JWTs signed with a shared secret (HS256) signing key. We strongly recommend relying on the Auth server as described above, or switching to a different signing key based on public key cryptography (RSA, Elliptic Curves) instead.

资源 #

🌐 Resources