魔法链接

魔法链接插件

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

安装

添加服务器插件

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

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: "[email protected]", // required, 发送魔法链接的电子邮件地址。    name: "my-name", // 用户显示名称。仅在用户首次注册时使用。    callbackURL: "/dashboard", // 验证后重定向的 URL。    newUserCallbackURL: "/welcome", // URL to redirect after new user signup.    errorCallbackURL: "/error", // URL to redirect if an error happens on verification If only callbackURL is provided but without an `errorCallbackURL` then they will be redirected to the callbackURL with an `error` query parameter.    metadata: { inviteId: "123" }, // 传递给 sendMagicLink 回调的附加元数据。});
Parameters
emailstringrequired

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

namestring

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

callbackURLstring

验证后重定向的 URL。

newUserCallbackURLstring

URL to redirect after new user signup.

errorCallbackURLstring

URL to redirect if an error happens on verification If only callbackURL is provided but without an errorCallbackURL then they will be redirected to the callbackURL with an error query parameter.

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", // 验证后重定向的 URL,如果未提供则返回会话。        newUserCallbackURL: "/welcome", // URL to redirect after new user signup.        errorCallbackURL: "/error", // URL to redirect if an error happens on verification. If only callbackURL is provided but without an `errorCallbackURL` then they will be redirected to the callbackURL with an `error` query parameter.    },});
Parameters
tokenstringrequired

验证令牌。

callbackURLstring

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

newUserCallbackURLstring

URL to redirect after new user signup.

errorCallbackURLstring

URL to redirect if an error happens on verification. If only callbackURL is provided but without an errorCallbackURL then they will be redirected to the callbackURL with an error query parameter.

配置选项

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

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

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

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

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

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

rateLimit:/sign-in/magic-link 和 /magic-link/verify 端点的速率限制。默认值为 { window: 60, max: 5 }。详情请参阅速率限制。

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

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

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

storeToken:控制 Better Auth 在创建验证标识符之前如何转换魔法链接令牌。默认值为 "plain"。

storeToken 可为以下值之一:

  • "plain":Better Auth 创建验证标识符前不转换令牌。
  • "hashed":创建标识符前使用默认哈希器对令牌进行哈希处理。
  • { type: "custom-hasher", hash: (token: string) => Promise<string> }:创建标识符前使用自定义哈希器转换令牌。

Better Auth 会在转换后的令牌前添加 magic-link:,然后应用全局 verification.storeIdentifier 设置。链接中发送的令牌值以及传给 sendMagicLink 的值均不会改变。自定义 storeToken 哈希器接收原始令牌,无需添加此前缀。

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

升级到带用途前缀的验证标识符后,请为升级前发出的魔法链接重新申请链接。新版本无法兑换旧链接,并会返回 INVALID_TOKEN。现有用户和账号无需迁移数据。请同时升级所有共用验证存储的服务器,以确保它们对哪些链接可兑换的判断一致。

当 secondaryStorage 为验证提供支持时(verification.storeInDatabase: false),原子单次使用保证要求你的二级存储公开 getAndDelete(Redis GETDEL、KV getAndDelete)。Better Auth 不会在验证令牌消耗时回退到单独的 get 和 delete 操作。使用二级存储验证的多实例部署必须配置实现了 getAndDelete 的后端。