docs/content/docs/plugins/magic-link.mdx
Magic link or email link is a way to authenticate users without a password. When a user enters their email, a link is sent to their email. When the user clicks on the link, they are authenticated.
Add the magic link plugin to your server:
```ts title="server.ts"
import { betterAuth } from "better-auth";
import { magicLink } from "better-auth/plugins"; // [!code highlight]
export const auth = betterAuth({
plugins: [
magicLink({ // [!code highlight]
sendMagicLink: async ({ email, token, url, metadata }, ctx) => { // [!code highlight]
// send email to user // [!code highlight]
} // [!code highlight]
}) // [!code highlight]
]
})
```
Add the magic link plugin to your client:
```ts title="auth-client.ts"
import { createAuthClient } from "better-auth/client";
import { magicLinkClient } from "better-auth/client/plugins"; // [!code highlight]
export const authClient = createAuthClient({
plugins: [
magicLinkClient() // [!code highlight]
]
});
```
To sign in with a magic link, you need to call signIn.magicLink with the user's email address. The sendMagicLink function is called to send the magic link to the user's email.
When you send the URL generated by the sendMagicLink function to a user, clicking the link will authenticate them and redirect them to the callbackURL specified in the signIn.magicLink function. If an error occurs, the user will be redirected to the callbackURL with an error query parameter.
If you want to handle the verification manually, (e.g, if you send the user a different URL), you can use the verify function.
sendMagicLink: The sendMagicLink function is called when a user requests a magic link. It takes an object with the following properties:
email: The email address of the user.url: The URL to be sent to the user. This URL contains the token.token: The token if you want to send the token with custom URL.metadata: Additional request metadata passed from signIn.magicLink.and a ctx context object as the second parameter.
expiresIn: specifies the time in seconds after which the magic link will expire. The default value is 300 seconds (5 minutes).
allowedAttempts (deprecated): Each verification call now consumes the token atomically on the first attempt, so retries always fail with ?error=INVALID_TOKEN regardless of this setting (see GHSA-hc7v-rggr-4hvx). The option is kept for source compatibility but ignored; multi-attempt redemption is no longer supported. Setting it to any value other than 1 emits a console.warn at startup (including 0, which previously rejected immediately and now has no effect).
disableSignUp: If set to true, the user will not be able to sign up using the magic link. The default value is false.
generateToken: The generateToken function is called to generate a token which is used to uniquely identify the user. The default value is a random string. There is one parameter:
email: The email address of the user.storeToken: The storeToken function controls how the magic link token is transformed before it is stored by Better Auth's verification layer. The default value is "plain".
The storeToken function can be one of the following:
"plain": The token is stored in plain text."hashed": The token is hashed using the default hasher.{ type: "custom-hasher", hash: (token: string) => Promise<string> }: The token is hashed using a custom hasher.The storage backend itself is controlled by the global verification config. If you configure secondaryStorage, magic link verification records can be stored there instead of the database.