BetterStarter logo
BetterStarter
Docs
GuidesAuth Providers

Magic Link Auth

Set up passwordless sign-in with one-click email magic links.

Docs are in beta — content is improving rapidly. Found something missing? Open an issue on GitHub or reach out on Twitter (X).

BetterStarter uses Better Auth with the magicLink plugin. Users enter their email and receive a one-time sign-in link.

Local Development Expectations

Plunk is optional in local development.

  • Without Plunk, BetterStarter logs the magic-link URL to the server console in development
  • With Plunk configured locally, BetterStarter sends a real email
  • In production, you need Plunk or another real email provider

1. Enable In Config

In src/appConfig.ts set:

magicLink: { enabled: true },

2. Fastest Local Test

Run the app without setting Plunk env vars:

pnpm dev

Then:

  1. Navigate to /auth/sign-in
  2. Enter your email and continue with the magic link flow
  3. Copy the generated URL from the server console
  4. Open that URL in your browser to complete sign-in

3. Optional: Set Up Plunk For Real Emails

  1. Create a free account at useplunk.com
  2. Verify your sending domain in the Plunk dashboard
  3. Copy your Secret API key

4. Set Environment Variables

# .env.local
PLUNK_SECRET_API_KEY=your_plunk_secret_api_key
TRANSACTIONAL_EMAIL=noreply@yourdomain.com

5. Test With Real Email Delivery

  1. Run pnpm dev
  2. Navigate to /auth/sign-in
  3. Enter your email and continue with the magic link flow
  4. Open the email and click Sign in
  5. In development, the generated URL is still logged to the server console

Configuration

Magic Link is configured in src/features/auth/index.ts:

  • magicLink({ sendMagicLink }) plugin is enabled when magicLink.enabled is true
  • Email sending is delegated to sendMagicLinkEmail in src/features/email/send.ts
  • Template and subject are defined in src/features/email/templates/MagicLinkEmail.tsx

In development, the auth layer also logs the generated magic-link URL before sending.

The default magic link email copy states that the link expires in 10 minutes.

Swapping Email Providers

To use another provider (Resend, SendGrid, SES, and so on), replace the transport logic in src/features/email/transport.ts.

Troubleshooting

  • No email received in local development — check the server console for the logged magic-link URL
  • No magic link email with Plunk enabled — verify PLUNK_SECRET_API_KEY, TRANSACTIONAL_EMAIL, and your sender domain setup
  • Link does not work — ensure APP_BASE_URL, BETTER_AUTH_URL, and deployment domain are correct
  • No magic link option in UI — check magicLink.enabled is true in src/appConfig.ts

On this page