Skip to main content

Modular, framework-agnostic passwordless authentication engine.

Project description

magic_link

PyPI License: MIT CI Coverage

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

  • 🔐 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 facadeMagicLinkService coordinates issuance, verification, rate limiting, and single-use guarantees.
  • 🛠️ CLI helpersmagic-link generate-config and magic-link test-email streamline 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

  1. Generate a configuration template:

    magic-link generate-config -o .env
    
  2. Fill in the environment variables (secret key, SMTP credentials, database connection, etc.).

  3. 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"})
    
  4. 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

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

  1. Follow the checklist in docs/release.md (trusted publisher + semver workflow).
  2. Alpha / beta versions: bump pyproject.toml, update CHANGELOG.md, tag, and publish.
  3. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

magic_link-1.0.0.tar.gz (24.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

magic_link-1.0.0-py3-none-any.whl (22.1 kB view details)

Uploaded Python 3

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page