Guide: Magic Links¶
This guide walks through the examples/magic_link application — a minimal FastAPI app with passwordless sign-in using magic links.
What we're building¶
- Magic link sign-in (no password required)
- Auto-registration on first login
- SQLite database via SQLAlchemy
- SMTP email delivery
Full server source¶
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastauth import FastAuth, FastAuthConfig
from fastauth.adapters.sqlalchemy import SQLAlchemyAdapter
from fastauth.email_transports.smtp import SMTPTransport
from fastauth.providers.magic_links import MagicLinksProvider
adapter = SQLAlchemyAdapter(
engine_url=os.environ.get("DATABASE_URL", "sqlite+aiosqlite:///./magic_links.db")
)
email_transport = SMTPTransport(
host=os.environ["SMTP_HOST"],
port=int(os.environ.get("SMTP_PORT", "587")),
username=os.environ["SMTP_USER"],
password=os.environ["SMTP_PASS"],
from_email=os.environ["SMTP_FROM"],
use_tls=False,
)
config = FastAuthConfig(
secret=os.environ["SECRET"],
providers=[MagicLinksProvider()],
adapter=adapter.user,
token_adapter=adapter.token,
email_transport=email_transport,
)
auth = FastAuth(config=config)
@asynccontextmanager
async def lifespan(app: FastAPI):
await adapter.create_tables()
yield
app = FastAPI(lifespan=lifespan)
auth.mount(app)
Install dependencies¶
Environment variables¶
| Variable | Example | Description |
|---|---|---|
SECRET |
change-me |
JWT signing secret |
SMTP_HOST |
localhost |
SMTP server host |
SMTP_PORT |
1025 |
SMTP server port |
SMTP_USER |
(empty) | SMTP username |
SMTP_PASS |
(empty) | SMTP password |
SMTP_FROM |
no-reply@example.com |
Sender address |
DATABASE_URL |
sqlite+aiosqlite:///./magic_links.db |
Database URL |
Local development with Mailpit¶
Mailpit runs a local SMTP server and provides a web UI to inspect sent emails — ideal for testing magic links without a real mail server.
Then set:
export SECRET=dev-secret
export SMTP_HOST=localhost
export SMTP_PORT=1025
export SMTP_USER=
export SMTP_PASS=
export SMTP_FROM=no-reply@example.com
Start the app:
Open http://localhost:8025 to see incoming emails.
Testing the flow¶
1 — Request a magic link¶
curl -X POST http://localhost:8000/auth/magic-links/login \
-H "Content-Type: application/json" \
-d '{"email": "alice@example.com"}'
Response:
The email appears in Mailpit at http://localhost:8025. It contains a link like:
2 — Exchange the token¶
Open the link in a browser, or call it directly:
Response:
The link is one-time use. Clicking it again returns 401.
3 — Access a protected route¶
Auto-registration¶
If the email is not in the database, FastAuth creates the user automatically (with no password). Subsequent logins with the same email sign in to that account. No separate registration endpoint is needed.
Token lifetime¶
The default is 15 minutes. Change it when configuring the provider:
Production notes¶
- Set
SECRETto a long random string (e.g.openssl rand -hex 32). - Use a real SMTP service — Resend, SendGrid, or Postmark all work via
SMTPTransport. - Use a persistent database (
DATABASE_URLpointing to PostgreSQL) so tokens survive restarts. - Set
base_urlinFastAuthConfigto your production domain so callback links point to the right host. - Enable
use_tls=TrueinSMTPTransportfor production SMTP servers.
Further reading¶
- Magic Links feature reference
- Magic Links provider reference
- Email Verification — same token/transport infrastructure