Skip to content

Magic Links

Magic links provide passwordless authentication. Users click a link in their email to log in — no password needed. AuthFort handles token generation and verification; you handle email delivery via event hooks.

  1. Request a magic link

    Via the built-in endpoint:

    POST /auth/magic-link
    Content-Type: application/json
    
    {"email": "user@example.com"}
    POST /auth/magic-link
    Content-Type: application/json
    
    {"email": "user@example.com"}

    Always returns 200 regardless of whether the email exists (prevents enumeration).

    Or programmatically:

    token = await auth.create_magic_link_token(email)
    # Returns token string, or None if user not found
    token = await auth.create_magic_link_token(email)
    # Returns token string, or None if user not found
  2. Deliver the link

    Use the magic_link_requested event hook:

    @auth.on("magic_link_requested")
    async def send_magic_link(event):
        await send_email(
            to=event.email,
            body=f"https://myapp.com/auth/magic?token={event.token}",
        )
    @auth.on("magic_link_requested")
    async def send_magic_link(event):
        await send_email(
            to=event.email,
            body=f"https://myapp.com/auth/magic?token={event.token}",
        )
  3. Verify and login

    Via the built-in endpoint:

    POST /auth/magic-link/verify
    Content-Type: application/json
    
    {"token": "..."}
    POST /auth/magic-link/verify
    Content-Type: application/json
    
    {"token": "..."}

    Returns an AuthResponse with tokens and user data. Sets cookies automatically if cookie mode is enabled.

    Or programmatically:

    result = await auth.verify_magic_link(token)
    # Returns AuthResponse with tokens and user
    result = await auth.verify_magic_link(token)
    # Returns AuthResponse with tokens and user

By default, magic links only work for existing users. Set allow_passwordless_signup=True to auto-create accounts:

auth = AuthFort(
    database_url="...",
    allow_passwordless_signup=True,
)
auth = AuthFort(
    database_url="...",
    allow_passwordless_signup=True,
)

Magic link login automatically sets email_verified=True — no separate verification step needed.

PropertyDetail
Token lifetimeSingle-use, expires after magic_link_ttl (default: 10 minutes)
Ban enforcementBanned users cannot use magic links
Token invalidationRequesting a new magic link invalidates any previous token

Emits magic_link_requested (includes token for delivery), magic_link_login, and optionally user_created (if auto-signup creates a new account).

See Events & Hooks for all events and their payloads.

await auth.requestMagicLink('user@example.com');

// User clicks link in email, your app extracts the token
const user = await auth.verifyMagicLink(token);
await auth.requestMagicLink('user@example.com');

// User clicks link in email, your app extracts the token
const user = await auth.verifyMagicLink(token);