认证

无密码邮箱登录

使用魔法链接或一次性密码(OTP)的邮箱登录方式


Supabase Auth 提供了多种无密码登录方式。无密码登录允许用户无需输入密码,通过点击确认链接或输入验证码即可完成登录。

无密码登录可以:

  • 提升用户体验:用户无需创建和记忆密码
  • 增强安全性:降低密码相关安全漏洞的风险
  • 减少支持负担:避免处理密码重置等密码相关流程

Supabase Auth 提供两种基于用户邮箱的无密码登录方式:

使用魔法链接

魔法链接是一种无密码登录方式,用户通过点击发送至邮箱的链接即可登录账户。魔法链接仅适用于邮箱地址,且为一次性使用。

启用魔法链接

包括魔法链接在内的邮箱认证方式默认已启用。

配置站点URL和任何额外的重定向URL。这些是用户点击魔法链接后允许跳转的唯一目标URL。对于托管项目,您可以在认证提供商页面修改这些URL;对于自托管项目,则需修改配置文件

默认情况下,用户每60 seconds只能请求一次魔法链接,且链接在1 hour后失效。

使用魔法链接登录

从客户端库调用"使用OTP登录"方法。

虽然方法名为"OTP",但默认情况下它会发送魔法链接。这两种方法的区别仅在于发送给用户的确认邮件内容。

如果用户尚未注册,默认会自动注册。要禁用此行为,请将shouldCreateUser选项设为false

1
2
3
4
5
6
7
8
9
10
async function () { const { , } = await ..({ : 'valid.email@supabase.io', : { // 如果不想自动创建用户,将此设为false : false, : 'https://example.com/welcome', }, })}

隐式流程到此结束。

如果使用PKCE流程,需要编辑魔法链接的邮件模板以发送令牌哈希:

1
2
3
4
<h2>魔法链接</h2><p>点击以下链接登录:</p><p><a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">登录</a></p>

/auth/confirm端点,将哈希交换为会话:

1
2
3
4
const { } = await ..({ : 'hash', : 'email',})

使用一次性密码(OTP)

电子邮件一次性密码(OTP)是一种无密码登录方式,用户通过输入发送到其邮箱的六位数验证码来登录账户。

启用电子邮件OTP

包括电子邮件OTP在内的电子邮件认证方法默认已启用。

电子邮件OTP与魔法链接(Magic Link)共享实现机制。要发送OTP而非魔法链接,需要修改魔法链接邮件模板。对于托管的Supabase项目,请前往控制台的邮件模板页面。对于自托管项目或本地开发环境,请参阅邮件模板指南

修改模板以包含{{ .Token }}变量,例如:

1
2
3
<h2>一次性登录验证码</h2><p>请输入此验证码:{{ .Token }}</p>

默认情况下,用户每60 seconds只能请求一次OTP,且OTP在1 hour后过期。可通过认证 > 提供商 > 电子邮件 > 电子邮件OTP有效期进行配置。为防止暴力破解攻击,不允许设置超过86400秒(一天)的过期时长。OTP有效期越长,攻击者进行暴力破解的时间窗口就越大。如果OTP有效期长达数天,攻击者将有更多机会通过重复尝试来猜测正确的OTP。

使用电子邮件OTP登录

第一步:向用户发送OTP验证码

获取用户的邮箱地址并调用客户端库中的"使用OTP登录"方法。

如果用户尚未注册,默认情况下会自动为其创建账户。如需禁用此行为,请将shouldCreateUser选项设为false

1
2
3
4
5
6
7
const { , } = await ..({ : 'valid.email@supabase.io', : { // 若不想自动创建用户,请将此设为false : false, },})

如果请求成功,您将收到一个error: null的响应和一个data对象(其中usersession均为null)。此时应提示用户检查邮箱收件箱。

1
2
3
4
5
6
7
{ "data": { "user": null, "session": null }, "error": null}

第二步:验证OTP以创建会话

为用户提供一个输入字段来输入一次性验证码。

调用客户端库中的"verify OTP"方法,传入用户的电子邮件地址、验证码和类型email

1
2
3
4
5
6
7
8
const { : { }, ,} = await ..({ : 'email@example.com', : '123456', : 'email',})

如果验证成功,用户即完成登录,您将收到一个有效的会话对象,格式如下:

1
2
3
4
5
6
7
{ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjI3MjkxNTc3LCJzdWIiOiJmYTA2NTQ1Zi1kYmI1LTQxY2EtYjk1NC1kOGUyOTg4YzcxOTEiLCJlbWFpbCI6IiIsInBob25lIjoiNjU4NzUyMjAyOSIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6InBob25lIn0sInVzZXJfbWV0YWRhdGEiOnt9LCJyb2xlIjoiYXV0aGVudGljYXRlZCJ9.1BqRi0NbS_yr1f6hnr4q3s1ylMR3c1vkiJ4e_N55dhM", "token_type": "bearer", "expires_in": 3600, "refresh_token": "LSp8LglPPvf0DxGMSj-vaQ", "user": {...}}