Skip to content

Magic Link

Magic-link sign-in lets a user authenticate by clicking a one-time link emailed to them — no password. It’s the link variant of passwordless auth (AnvilBase also supports a 6-digit email OTP code; see Email OTP).

Enable it

Magic link is gated per project on the magic_link_enabled auth setting. Turn it on (see Auth settings):

Terminal window
curl -X PATCH http://localhost:39001/api/v1/projects/<id>/auth \
-H "Authorization: Bearer $ANVILBASE_TOKEN" -H "Content-Type: application/json" \
-d '{ "magic_link_enabled": true }'

When it’s off, POST /magiclink returns 422 otp_disabled.

The flow

  1. Your app calls POST /v1/auth/<project_id>/auth/v1/magiclink with { email } (supabase-js signInWithOtp({ email })). AnvilBase always returns an empty 200 — it never reveals whether the email exists.
  2. AnvilBase emails the user a magic link, rendered from the project’s pre-built magic_link email template and sent via the project’s SMTP config.
  3. The user clicks the link, which lands on …/auth/v1/verify?type=magiclink&token=<token>. AnvilBase verifies the token and mints a project session (JWT pair).

SDK example

// Send the link. redirect_to (optional) must be on the AUTH_ALLOWED_REDIRECT_URLS
// allow-list — otherwise the call is rejected with 400.
await db.auth.signInWithOtp({
email: "ada@example.com",
options: { emailRedirectTo: "https://app.example.com/welcome" },
})

The same method exists on every SDK (sign_in_with_otp in Python/Rust/Elixir, SignInWithOtp in Go, signInWithOtp in Kotlin/Swift).

Allow-listing the redirect target

redirect_to (emailRedirectTo) is validated against the auth service’s AUTH_ALLOWED_REDIRECT_URLS allow-list — a full-URL match on scheme + host + path, comma-separated. A target that isn’t on the list is rejected with 400, and the list is secure-by-default: when it’s empty, no redirect target is allowed (so set it before relying on emailRedirectTo).

AUTH_ALLOWED_REDIRECT_URLS is a deployment environment variable on the auth service, not a per-project setting — configure it in your .env / compose override (see Configuration). It is the same allow-list enforced for OAuth redirect_to; for the security rationale see OAuth Providers → open-redirect protection and Network Security.

Customise the email

Edit the magic_link template under PUT /api/v1/projects/<id>/email/templates/magic_link. See Email & Templates. The template renders the action URL the user clicks.

Rate limits

Magic-link sends are throttled by a per-IP guard (5 sends/min per source IP) and a per-recipient hourly cap (OTP_EMAIL_SEND_MAX, default 5, over OTP_SEND_WINDOW_SECS). Over the cap returns 429 over_email_send_rate_limit with Retry-After; the cap is recipient-keyed so it never leaks whether an account exists. See Network Security and Configuration.

Next: Multi-factor auth.