Overview
A modern, secure, and self-hosted passwordless authentication solution
Passwordless Auth is a self-hosted identity and authentication server designed for small teams and internal tools. It provides modern passwordless login mechanismsβmagic links delivered via email, WebAuthn (passkeys), and TOTP fallbackβwhile issuing JWTs for session management. No third-party identity provider is required; all state is under your control, with revocable short-lived sessions and refresh tokens.
π― Goals & Motivation
Eliminate Passwords
Reduce risk by avoiding traditional passwords in favor of magic links, passkeys, and one-time TOTP codes.
Self-Hosted Control
No reliance on external SaaS for auth; all data, tokens, and credentials live under your infrastructure.
Modern UX
Support for WebAuthn (biometric or hardware keys), magic link convenience, and TOTP as backup.
Secure Sessions
JWT access + refresh tokens with revocation and lifetime policies for maximum security.
Reliable Delivery
Email queueing with retries to ensure magic links arrive even under transient SMTP issues.
High Performance
Built with Rust for safety, speed, and efficiency. Production-ready from day one.
Core Features
Three powerful authentication methods, one unified system
π§ Magic Link Flow
Email-based one-time login links with expiration and single-use semantics. Perfect for quick, secure access without memorizing credentials.
- β Email-based authentication
- β One-time use tokens
- β Configurable expiration
- β Reliable queue system
π TOTP Flow
Time-based one-time passwords for fallback or second factor. Compatible with Google Authenticator, Authy, and other TOTP apps.
- β Industry-standard TOTP
- β QR code enrollment
- β Clock skew tolerance
- β Offline capable
π WebAuthn Flow
Strong cryptographic passwordless authentication using platform or roaming authenticators. Biometric and hardware key support.
- β FIDO2 compliant
- β Biometric authentication
- β Hardware key support
- β Phishing resistant
π§ Core Technologies
| Technology | Purpose | Benefits |
|---|---|---|
| π¦ Rust | Implementation language | Memory safety, performance, reliability |
| β‘ Axum | HTTP server framework | Fast, ergonomic, type-safe web APIs |
| ποΈ SQLite | Embedded persistence | Light, portable, zero-config database |
| π« JWT | Token-based sessions | Stateless, scalable authentication |
| π OpenAPI | API specification | Auto-generated clients, documentation |
| π³ Docker | Containerization | Consistent deployment, easy orchestration |
Architecture
Comprehensive system design with visual flow diagrams
ποΈ High-Level Architecture Overview
flowchart TD
User[User / Client]
Choose[Select Auth Method]
User --> Choose
subgraph MagicLink[Magic Link Flow]
direction TB
MLRequest[POST /request/magic]
CreateToken[Generate one-time token]
EnqueueEmail[Enqueue email job]
EmailWorker[Email worker picks job]
SendEmail[Send via SMTP]
ClickLink[User clicks link]
VerifyToken[Validate and mark used]
IssueJWT_ML[Issue JWTs]
end
subgraph TOTP[TOTP Flow]
direction TB
TOTPEnroll[POST /totp/enroll]
StoreTOTP[Store TOTP secret]
TOTPVerify[POST /totp/verify]
ValidateTOTP[Validate code]
IssueJWT_TOTP[Issue JWTs]
end
subgraph WebAuthn[WebAuthn Flow]
direction TB
WebRegOptions[POST /webauthn/register/options]
CompleteReg[POST /webauthn/register/complete]
SaveCred[Persist credential]
WebLoginOptions[POST /webauthn/login/options]
CompleteLogin[POST /webauthn/login/complete]
IssueJWT_Web[Issue JWTs]
end
subgraph Tokens[Token Management]
direction TB
RefreshReq[POST /token/refresh]
ValidateRefresh[Validate refresh token]
IssueNewJWT[Issue new JWTs]
end
subgraph DB[SQLite Database]
direction TB
Users[Users Table]
MagicTokens[Magic Link Tokens]
TOTPSecrets[TOTP Secrets]
WebCreds[WebAuthn Credentials]
RefreshTokens[Refresh Tokens]
EmailQueue[Email Queue]
end
Choose --> MLRequest
MLRequest --> CreateToken --> EnqueueEmail
EnqueueEmail --> EmailQueue
EmailQueue --> EmailWorker --> SendEmail
SendEmail --> ClickLink --> VerifyToken --> IssueJWT_ML --> User
Choose --> TOTPEnroll --> StoreTOTP
StoreTOTP --> TOTPSecrets
TOTPVerify --> ValidateTOTP --> IssueJWT_TOTP --> User
Choose --> WebRegOptions --> CompleteReg --> SaveCred
SaveCred --> WebCreds
WebLoginOptions --> CompleteLogin --> IssueJWT_Web --> User
User --> RefreshReq --> ValidateRefresh
ValidateRefresh --> RefreshTokens
ValidateRefresh --> IssueNewJWT --> User
π Component Class Diagram
classDiagram
class AuthServer {
+Config config
+start()
+shutdown()
}
class MagicLinkService {
+request_link(email)
+verify(token)
+generate_token()
}
class TOTPService {
+enroll(email)
+verify(email, code)
+generate_secret()
}
class WebAuthnService {
+begin_registration(email)
+complete_registration(pending_id, resp)
+begin_login(email)
+complete_login(pending_id, resp)
}
class JWTService {
+create_access(user_id)
+create_refresh(user_id)
+verify(token)
+revoke_refresh(token)
}
class EmailQueueWorker {
+enqueue(to, subject, text, html)
+process_due()
+retry_failed()
}
class SMTPProvider {
+send(to, subject, body)
+configure(host, port, username, password)
}
class SQLiteDB {
+execute(query)
+query(query)
+transaction()
}
class User {
-String id
-String email
-String totp_secret
-credentials
}
class MagicLinkToken {
-String token
-DateTime expires_at
-bool used
-String user_id
}
class RefreshToken {
-String token
-DateTime expires_at
-bool revoked
-String user_id
}
AuthServer --> MagicLinkService
AuthServer --> TOTPService
AuthServer --> WebAuthnService
AuthServer --> JWTService
AuthServer --> SQLiteDB
MagicLinkService --> SQLiteDB
MagicLinkService --> EmailQueueWorker
EmailQueueWorker --> SMTPProvider
EmailQueueWorker --> SQLiteDB
TOTPService --> SQLiteDB
WebAuthnService --> SQLiteDB
JWTService --> SQLiteDB
SQLiteDB --> User
SQLiteDB --> MagicLinkToken
SQLiteDB --> RefreshToken
π Authentication Sequence
sequenceDiagram
participant U as User
participant C as Client App
participant S as Auth Server
participant DB as Database
participant SMTP as SMTP Server
Note over U,SMTP: Magic Link Authentication Flow
U->>C: Enter email
C->>S: POST /request/magic
S->>DB: Create magic token
S->>DB: Enqueue email
S-->>C: 200 OK silent
loop Email Worker
S->>DB: Fetch pending emails
S->>SMTP: Send magic link
SMTP-->>U: Email delivered
end
U->>C: Click magic link
C->>S: GET /verify/magic
S->>DB: Validate token
S->>DB: Mark token as used
S->>DB: Store refresh token
S-->>C: Return tokens
C->>C: Store tokens
Note over U,SMTP: Subsequent Requests
C->>S: API request with access token
S->>S: Verify JWT
S-->>C: Protected resource
Note over U,SMTP: Token Refresh
C->>S: POST /token/refresh
S->>DB: Validate refresh token
S->>DB: Create new refresh token
S-->>C: Return new tokens
Quick Start
Get up and running in minutes
- Rust toolchain (install via rustup)
- Cargo (included with Rust)
- Make (optional, for convenience commands)
- Docker & Docker Compose (optional, for containerized deployment)
π₯ Installation
# Clone the repository
git clone https://github.com/yourusername/passwordless-auth.git
cd passwordless-auth
# Build the project
make build
# Or build manually
cargo build --release
βοΈ Configuration
Edit config.toml with your settings:
# JWT Configuration
jwt_secret = "your-super-secret-key-here-min-32-chars"
access_token_expiry_seconds = 900 # 15 minutes
refresh_token_expiry_seconds = 604800 # 7 days
# Magic Link Settings
magic_link_expiry_seconds = 600
magic_link_base_url = "http://localhost:3000/verify/magic"
# SMTP Configuration
smtp_host = "smtp.example.com"
smtp_port = 587
smtp_username = "your-email@example.com"
smtp_password = "your-smtp-password"
email_from = "no-reply@example.com"
# WebAuthn Settings
webauthn_rp_id = "localhost"
webauthn_origin = "http://localhost:3000"
webauthn_rp_name = "Passwordless Auth"
# Database
database_path = "auth.db"
π Running the Server
# Start the auth server
./target/release/passwordless-auth
# In another terminal, start the email worker
./target/release/email-worker
# Or use Docker Compose
docker-compose up --build
π§ͺ Testing the API
# Request a magic link
curl -X POST http://localhost:3000/request/magic \
-H "Content-Type: application/json" \
-d '{"email":"alice@example.com"}'
# Verify the magic link (get token from email or database)
curl "http://localhost:3000/verify/magic?token=YOUR_TOKEN_HERE"
# Response: {"access_token":"...", "refresh_token":"..."}
# Refresh tokens
curl -X POST http://localhost:3000/token/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token":"YOUR_REFRESH_TOKEN"}'
API Reference
Complete HTTP API documentation
π§ Magic Link Endpoints
Description: Request a magic login link to be sent via email
Request Body:
{
"email": "alice@example.com"
}
Response: 200 OK (always succeeds silently to prevent email enumeration)
Description: Verify a magic link token and receive JWTs
Query Parameters:
- token (required): The magic link token from email
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
π TOTP Endpoints
Description: Enroll a TOTP authenticator for an email
Request Body:
{
"email": "alice@example.com"
}
Response:
{
"secret": "JBSWY3DPEHPK3PXP",
"otpauth_url": "otpauth://totp/PasswordlessAuth:alice@example.com?secret=JBSWY3DPEHPK3PXP&issuer=PasswordlessAuth"
}
Description: Verify a TOTP code and receive JWTs
Request Body:
{
"email": "alice@example.com",
"code": "123456"
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
π WebAuthn Endpoints
Description: Get WebAuthn registration options
Request Body:
{
"email": "alice@example.com"
}
Response: WebAuthn PublicKeyCredentialCreationOptions
Description: Complete WebAuthn registration
Request Body:
{
"pending_id": "uuid-from-options-response",
"response": { /* PublicKeyCredential from browser */ }
}
Description: Get WebAuthn login options
Request Body:
{
"email": "alice@example.com"
}
Response: WebAuthn PublicKeyCredentialRequestOptions
Description: Complete WebAuthn login and receive JWTs
Request Body:
{
"pending_id": "uuid-from-options-response",
"response": { /* PublicKeyCredential from browser */ }
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
π« Token Management
Description: Refresh access token using refresh token
Request Body:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Documentation
Comprehensive guides and references
π Key Concepts
π Security Primitives
- HMAC & Signed Tokens: JWTs are signed using HS256 with a secret key to prevent forgery
- Challenge/Response: WebAuthn uses cryptographic challenges to prove credential possession
- One-time Protection: Magic link tokens are marked as used and expire after single use
- TOTP Windowing: Small clock skew tolerance while preventing code reuse
- Token Revocation: Refresh tokens stored server-side for immediate revocation capability
π§ Email Queue Worker
To improve reliability of magic link delivery, emails are enqueued in email_queue and retried with exponential backoff:
- Fetches due pending emails from queue
- Marks emails as "sending" to prevent duplicate delivery
- Attempts delivery via SMTP
- On failure: updates next_try_at with exponential backoff
- On success: marks email as sent
This design makes the system resilient to transient SMTP issues.
π§ͺ Testing
Unit Tests: Cover JWT creation/verification, magic link lifecycle, TOTP generation/validation, and refresh token management.
Integration Tests: Simulate full authentication flows including magic link end-to-end, token refresh, TOTP enrollment/verification, and WebAuthn option retrieval.
# Run all tests
make test
# Or directly with cargo
cargo test
# Run specific test
cargo test test_magic_link_flow
π³ Docker Deployment
Deploy using Docker Compose for production-ready setup:
# Build Docker image
make docker-build
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
Services:
- auth: Primary authentication server (port 3000)
- email-worker: Background email queue processor
π Security Considerations
- Secret Management: Use strong, random jwt_secret (min 32 chars). Store in environment variables or secrets manager.
- Token Expiry: Keep access tokens short-lived (15 min). Refresh tokens should be revocable.
- TLS/HTTPS: Always deploy behind TLS termination (Caddy, Nginx, or cloud load balancer).
- Rate Limiting: Implement per-IP/email throttling to prevent abuse and enumeration.
- Email Security: Use SPF, DKIM, and DMARC for email authentication.
- Database Backups: Regular backups of SQLite database containing users and tokens.
- Monitoring: Log authentication attempts, failures, and token issuance for audit trails.
- WebAuthn Origin: Ensure webauthn_origin matches your actual domain.
π οΈ Troubleshooting
| Issue | Possible Cause | Solution |
|---|---|---|
| Magic link email not arriving | SMTP misconfiguration | Check email_queue table, verify SMTP credentials, run email-worker |
| Token expired error | Token lifetime passed | Request new magic link or use refresh token |
| JWT verification fails | Wrong secret or malformed token | Verify jwt_secret matches across all instances |
| WebAuthn errors | Origin/RP mismatch | Ensure webauthn_origin and rp_id match client domain |
| Database locked | Concurrent SQLite access | WAL mode enabled by default; avoid long transactions |
| Refresh token invalid | Token revoked or expired | Re-authenticate via magic link, TOTP, or WebAuthn |
π Extension Points
Backend Swap
Replace SQLite with PostgreSQL or MySQL for larger deployments and better concurrency.
Session Management
Add endpoints to list active sessions and revoke specific refresh tokens per user.
Rate Limiting
Implement per-IP and per-email throttling using middleware or external service.
Rich Email Templates
Upgrade to Handlebars or Tera templating for branded HTML emails.
Metrics & Monitoring
Export Prometheus metrics for auth success/failure, queue depth, and token issuance.
Admin Dashboard
Build a web UI to manage users, view challenges, and revoke tokens.
Contributing
Help make Passwordless Auth even better
- Fork the repository on GitHub
- Create a feature branch: git checkout -b feature/your-feature
- Make your changes and add tests
- Ensure all tests pass: cargo test
- Format code: cargo fmt
- Run clippy: cargo clippy
- Commit your changes with clear messages
- Push to your fork and submit a pull request
π High-Value Contributions
- β Pluggable storage backends (Redis, PostgreSQL)
- β WebAuthn client-side helper library
- β Alternative delivery methods (SMS, webhook)
- β Admin UI for user and session management
- β Performance optimizations and benchmarks
- β Additional authentication methods
- β Improved documentation and examples
Glossary
| Term | Definition |
|---|---|
| Magic Link | One-time login URL sent by email that expires after use |
| TOTP | Time-based One-Time Password, standard for 2FA authenticator apps |
| WebAuthn | Browser-native cryptographic authentication standard (FIDO2) |
| JWT | JSON Web Token, signed token representing session identity |
| Access Token | Short-lived JWT for API access (typically 15 minutes) |
| Refresh Token | Longer-lived token for obtaining new access tokens (typically 7 days) |
| Email Queue | Persistent queue with retry mechanism for reliable email delivery |
| RP (Relying Party) | The service (this server) in WebAuthn terminology |
| Passkey | User-friendly term for WebAuthn credentials (e.g., fingerprint, Face ID) |