Modular, framework-agnostic passwordless authentication engine.
Project description
magic_link
A modular, framework-agnostic engine for delivering passwordless authentication via secure magic links. The project follows a “minimal core + opt-in extras” philosophy so you can embed the library inside any Python stack without surrendering control of storage, email, or infrastructure.
Docs live in
/docs. This README highlights the essentials; detailed guides, recipes, and release instructions are all linked below.
Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Extras
- CLI Utilities
- Documentation
- Testing
- Release Process
- Contributing
- License
Features
- 🔐 Secure token engine – deterministic HMAC signing, hashing, TTL enforcement, property-based tests.
- 🗃️ Pluggable storage – in-memory for dev, SQLAlchemy for RDBMS, Redis for low-latency workloads.
- ✉️ Mailer registry – SMTP implementation plus extensible template hooks.
- 🎛️ Service facade –
MagicLinkServicecoordinates issuance, verification, rate limiting, and single-use guarantees. - 🛠️ CLI helpers –
magic-link generate-configandmagic-link test-emailstreamline setup and diagnostics. - 📚 Extensive documentation – quickstarts, framework recipes (FastAPI, Flask), and in-depth guides for email, migrations, and security.
- ✅ 100% test coverage – unit, integration, and property-based suites validated in CI against live PostgreSQL, Redis, and audo SMTP servers.
Requirements
- Python 3.8+
- Optional services depending on extras:
- PostgreSQL (or any SQLAlchemy-supported database) for the SQL backend
- Redis 5+ for the Redis backend
- SMTP relay for outbound email
Installation
Core library:
pip install magic-link
With common extras:
pip install "magic-link[sqlalchemy,redis,smtp]"
Add cli if you want the command-line utilities bundled:
pip install "magic-link[sqlalchemy,redis,smtp,cli]"
Quick Start
-
Generate a configuration template:
magic-link generate-config -o .env
-
Fill in the environment variables (secret key, SMTP credentials, database connection, etc.).
-
Wire the library into your framework. For FastAPI:
from fastapi import FastAPI, HTTPException from fastapi.responses import JSONResponse from magic_link import MagicLinkConfig, MagicLinkService from magic_link.interfaces import MagicLinkMessage from magic_link.mailer import create_mailer from magic_link.storage.redis import RedisStorage app = FastAPI() config = MagicLinkConfig.from_env() storage = RedisStorage.from_url("redis://localhost:6379/0") # see docs for helper service = MagicLinkService(config=config, storage=storage) mailer = create_mailer(config) @app.post("/auth/magic-link") async def issue(payload: dict[str, str]) -> JSONResponse: email = payload.get("email") if not email: raise HTTPException(status_code=400, detail="Email is required") service.enforce_rate_limit(email) issued = service.issue_token(email) link = f"{config.base_url}{config.login_path}?token={issued.token}" mailer.send_magic_link(MagicLinkMessage(recipient=email, link=link, subject="Sign in", expires_at=issued.expires_at)) return JSONResponse({"status": "sent"})
-
Verify tokens using
service.verify_token(...)in your callback endpoint.
For a complete, copy-pasteable example (including Flask), consult the Quickstart guide and recipes.
Extras
| Extra | Installs | Purpose |
|---|---|---|
sqlalchemy |
SQLAlchemy, psycopg[binary] |
Persistent token storage in relational DBs |
redis |
redis, hiredis |
High-throughput storage + rate limiting |
smtp |
email-validator |
SMTP mailer backend and email utilities |
cli |
click |
Command-line helpers (magic-link CLI) |
CLI Utilities
# Print an annotated configuration template
magic-link generate-config
# Send a test email using your configured mailer
magic-link test-email user@example.com
Documentation
- Overview & FastAPI quickstart
- Step-by-step Quickstart
- Framework recipes – Flask and more
- Guides – email templates, database migrations, security considerations
- Architecture
- Release process
Testing
pip install -e ".[dev,sqlalchemy,redis,smtp,cli]"
pytest --cov=magic_link
CI runs the full suite (unit, property-based, integration) against PostgreSQL, Redis, and a local SMTP server. Coverage must stay ≥95% (currently 100%).
Release Process
- Follow the checklist in docs/release.md (trusted publisher + semver workflow).
- Alpha / beta versions: bump
pyproject.toml, updateCHANGELOG.md, tag, and publish. - Official releases are cut via GitHub Releases, which triggers the trusted publisher workflow to upload builds to PyPI.
Contributing
- Open an issue or draft PR for discussion.
- Ensure tests and linters pass (
pytest,ruff check,black --check,mypy). - Update documentation for user-facing changes.
License
Distributed under the MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file magic_link-1.0.0.tar.gz.
File metadata
- Download URL: magic_link-1.0.0.tar.gz
- Upload date:
- Size: 24.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2236eed2e8d3952df1834abee6338d8c85f64b42b90129df47edf4aa6eeb2b19
|
|
| MD5 |
0a4be4ddca3009566627e05520ac42ea
|
|
| BLAKE2b-256 |
3a0899c55a4c7b85bcb251c72b93fa5d60bd93f073fc3f0e1377fbac2c57c7d1
|
Provenance
The following attestation bundles were made for magic_link-1.0.0.tar.gz:
Publisher:
release.yml on h8v6/magic-link
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
magic_link-1.0.0.tar.gz -
Subject digest:
2236eed2e8d3952df1834abee6338d8c85f64b42b90129df47edf4aa6eeb2b19 - Sigstore transparency entry: 622365331
- Sigstore integration time:
-
Permalink:
h8v6/magic-link@b460591414d1983fea01007c2e6126551104626f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/h8v6
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b460591414d1983fea01007c2e6126551104626f -
Trigger Event:
release
-
Statement type:
File details
Details for the file magic_link-1.0.0-py3-none-any.whl.
File metadata
- Download URL: magic_link-1.0.0-py3-none-any.whl
- Upload date:
- Size: 22.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42dcf7a2f92cac1f2cd196505afcdb10cc1f518a7d29511cea29e51f03a2b7d9
|
|
| MD5 |
ea1e75e3b29ac320d211643ff4d890a1
|
|
| BLAKE2b-256 |
48920f00e86bb7d621c22375ae4644e7fb51b477a464c9450e105f0c1851536c
|
Provenance
The following attestation bundles were made for magic_link-1.0.0-py3-none-any.whl:
Publisher:
release.yml on h8v6/magic-link
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
magic_link-1.0.0-py3-none-any.whl -
Subject digest:
42dcf7a2f92cac1f2cd196505afcdb10cc1f518a7d29511cea29e51f03a2b7d9 - Sigstore transparency entry: 622365336
- Sigstore integration time:
-
Permalink:
h8v6/magic-link@b460591414d1983fea01007c2e6126551104626f -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/h8v6
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@b460591414d1983fea01007c2e6126551104626f -
Trigger Event:
release
-
Statement type: