Skip to content

Magic links provider

Passwordless sign-in via a one-time link emailed to the user. Unknown emails are auto-registered on first use.

from fastauth.providers.magic_links import MagicLinksProvider

provider = MagicLinksProvider()            # default max_age=900 (15 min)
provider = MagicLinksProvider(max_age=600) # 10-min request TTL

max_age controls how long a magic-link login-request token is valid (stored as type "magic_link_login_request"). Requires the email extra for SMTP, or any EmailTransport. token_adapter is required — MagicLinksProvider.send_login_request raises ConfigError("token_adapter is required for magic links") on first login attempt otherwise.

Endpoints

Method Path Auth Request Response
POST /auth/magic-links/login {email} {message: "Magic link sent — check your email"}
GET /auth/magic-links/callback ?token=... cookie: MessageResponse; json: TokenResponse

Flow

sequenceDiagram
    participant U as User
    participant A as App
    participant T as TokenAdapter
    U->>A: POST /auth/magic-links/login {email}
    alt email unknown
        A->>A: create user with hashed_password=None
        A->>A: assign default_role (if role_adapter)
        A->>A: fire on_signup
    end
    A->>T: store hash(token), TTL=max_age
    A-->>U: 200 "Magic link sent — check your email"
    A-->>U: email with {base_url}/auth/magic-links/callback?token=...
    U->>A: GET /auth/magic-links/callback?token=...
    A->>T: consume hash(token) (atomic)
    alt not email_verified
        A->>A: set email_verified=True, fire on_email_verify
    end
    A->>A: fire allow_signin(user, "magic_link"), 403 if False
    A->>A: issue tokens, cookie mode sets cookies
    A-->>U: cookie: MessageResponse, json: TokenResponse

Auto-registration

Unknown emails are auto-registered with hashed_password=None. This means any email can create an account. If that is not acceptable, you can:

  • gate it in allow_signin(user, "magic_link") returning False for freshly created users (the hook receives the post-creation UserData), or
  • not expose the magic-links router while keeping credentials.

A pre-create hook is not currently available. (needs maintainer clarification on whether one will be added)

Hooks

  • on_signup (only on auto-registration)
  • on_magic_link_sent (after the email is sent)
  • on_email_verify (if email_verified=False at callback)
  • allow_signin(user, "magic_link")False403
  • on_signinJSON mode only; in cookie mode it is not fired. (needs maintainer clarification)

Common mistakes

  • ConfigError: token_adapter is required for magic linksMagicLinksProvider.send_login_request raises this at the first login attempt if token_adapter is None.
  • Forgetting base_url — the link in the email points at localhost:8000.
  • debug=True in production — relaxes cookie security.
  • Multi-worker SMTPSMTPTransport is async and stateless; safe under workers.