Skip to main content
View as Markdown

Magic Link & Email OTP

Two ways to sign a user in without a password, both of which prove control of an inbox: a link they click, or a code they type. Neither stores a password, so neither has a password to leak or reset.

They are enabled through different mechanisms — the link is a strategy entry, the code is not. That asymmetry is the one thing to get right on this page.

A strategy entry. The user submits their email, receives a one-time link, and is signed in by following it.

auth:
  strategies:
    - type: magicLink
      expirationMinutes: 30
Property Description
expirationMinutes Link lifetime in minutes (positive integer). Defaults to 15.

The default 15 minutes assumes the user is waiting on the mail. Stretch it when your audience checks email on a phone, later; shorten it when the link grants access to something sensitive, since a live link in an inbox is a live credential.

The message body is rendered from the magicLink email template when you supply one, with $url substituted for the link.

Enabling Email-OTP

Email-OTP delivers a numeric one-time code instead of a link — better on a device where following a link would break the flow, and easier to read aloud over a phone.

There is no type: emailOtp strategy entry. The flow activates when you define the emailOtp email template; its presence is what mounts the plugin.

auth:
  strategies:
    - type: emailAndPassword
  emailTemplates:
    emailOtp:
      subject: Your sign-in code
      text: 'Your verification code is $code. It expires shortly.'

$code is substituted with the generated one-time code. Note the strategy array above declares only emailAndPassword — email-OTP rides alongside whatever strategies you declared, it does not replace them.

Both Need SMTP

A passwordless flow that cannot send mail cannot sign anyone in. When SMTP is unset the app boots with email disabled and logs a warning — sign-in attempts then fail silently, with the user waiting on a message that was never sent.

Configure SMTP before shipping either flow, and prefer keeping emailAndPassword declared alongside them while you do: it gives you a working way in if mail delivery breaks. See Environment Variables for the SMTP settings.

Last updated July 27, 2026

This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta — contributions and corrections are welcome.

Built with Sovrium