魔法链接

魔法链接插件

魔法链接或电子邮件链接是一种无需密码即可验证用户身份的方法。当用户输入其电子邮件时,会向其邮箱发送一个链接。用户点击该链接后,即完成身份验证。

安装

添加服务器插件

将魔法链接插件添加到服务器:

server.ts
import { betterAuth } from "better-auth";
import { magicLink } from "better-auth/plugins";  

export const auth = betterAuth({
    plugins: [
        magicLink({ 
            sendMagicLink: async ({ email, token, url, metadata }, ctx) => { 
                // 向用户发送邮件
            } 
        }) 
    ]
})

添加客户端插件

将魔法链接插件添加到客户端:

auth-client.ts
import { createAuthClient } from "better-auth/client";
import { magicLinkClient } from "better-auth/client/plugins"; 

export const authClient = createAuthClient({
    plugins: [
        magicLinkClient() 
    ]
});

使用方法

使用魔法链接登录

POST/sign-in/magic-link
const { data, error } = await authClient.signIn.magicLink({    email: "user@email.com", // required    name: "my-name",    callbackURL: "/dashboard",    newUserCallbackURL: "/welcome",    errorCallbackURL: "/error",    metadata: { inviteId: "123" },});
Parameters
emailstringrequired

发送魔法链接的电子邮件地址。

namestring

用户显示名称。仅在用户首次注册时使用。

callbackURLstring

验证后重定向的 URL。

newUserCallbackURLstring

新用户注册后重定向的 URL

errorCallbackURLstring

验证出错时重定向的 URL 如果只提供了 callbackURL 而没有 errorCallbackURL,则会带有 error 查询参数重定向到 callbackURL。

metadataRecord<string, any>

传递给 sendMagicLink 回调的附加元数据。

如果用户尚未注册,除非将 disableSignUp 设置为 true,否则用户将自动注册。

验证魔法链接

当你将 sendMagicLink 函数生成的 URL 发送给用户时,用户点击链接后将完成身份验证,并重定向到 signIn.magicLink 函数中指定的 callbackURL。如果发生错误,用户会被重定向到带有错误查询参数的 callbackURL

如果未提供 callbackURL,用户将被重定向到根网址。

如果你想手动处理验证(例如,如果你向用户发送了不同的 URL),可以使用 verify 函数。

GET/magic-link/verify
const { data, error } = await authClient.magicLink.verify({    query: {        token: "123456", // required        callbackURL: "/dashboard",    },});
Parameters
tokenstringrequired

验证令牌。

callbackURLstring

验证后重定向的 URL,如果未提供则返回会话。

配置选项

sendMagicLink:当用户请求魔法链接时调用 sendMagicLink 函数。该函数接收一个包含以下属性的对象:

  • email: 用户的电子邮件地址。
  • url: 要发送给用户的 URL。此 URL 包含令牌。
  • token: 如果你想通过自定义 URL 发送令牌,则使用此令牌。
  • metadata: 从 signIn.magicLink 传递的附加请求元数据。

此外,函数的第二个参数为上下文对象 ctx

expiresIn:指定魔法链接过期的时间(以秒为单位)。默认值为 300 秒(5 分钟)。

allowedAttempts (已弃用):现在每次验证调用都会在首次尝试时以原子方式消费令牌,因此无论此设置如何,重试都会始终失败并返回 ?error=INVALID_TOKEN(参见 GHSA-hc7v-rggr-4hvx)。该选项仅为保持源码兼容而保留,但会被忽略;不再支持多次尝试兑换。将其设置为除 1 之外的任何值都会在启动时发出 console.warn(包括 0,它以前会立即拒绝,而现在不再生效)。

disableSignUp:如果设置为 true,用户将无法使用魔法链接进行注册。默认值为 false

generateToken:用于生成唯一标识用户的令牌的函数。默认生成一个随机字符串。函数参数:

  • email: 用户的电子邮件地址。

使用 generateToken 时,请确保返回的字符串难以猜测,因为它用于以保密方式验证用户身份。默认情况下,我们返回一个长度较长且密码学安全的字符串。

storeTokenstoreToken 函数控制魔法链接令牌在被 Better Auth 的验证层存储前的转换方式。默认值为 "plain"

storeToken 可为以下之一:

  • "plain": 令牌以明文形式存储。
  • "hashed": 使用默认哈希器对令牌进行哈希处理。
  • { type: "custom-hasher", hash: (token: string) => Promise<string> }: 使用自定义哈希器对令牌进行哈希处理。

存储后端本身由全局 verification 配置控制。如果你配置了 secondaryStorage,魔法链接验证记录可以存储在那里,而不是数据库中。

secondaryStorage 承载验证(verification.storeInDatabase: false)时,来自 GHSA-hc7v-rggr-4hvx 的原子性单次使用保证要求你的 secondary storage 提供 getAndDelete(Redis GETDEL,KV getAndDelete)。如果实现只提供 getdelete,则消费操作会回退到进程内的 JavaScript 锁,而该锁无法在多个应用实例之间协调。使用 secondary-storage 验证的多实例部署必须配置一个实现了 getAndDelete 的后端。