{"id":26818013,"url":"https://github.com/itsmeadarsh2008/haze","last_synced_at":"2025-03-30T04:20:00.067Z","repository":{"id":282874380,"uuid":"949898642","full_name":"itsmeadarsh2008/haze","owner":"itsmeadarsh2008","description":"Lightning-fast Magic Links. 🍵 Beginner-friendly. Easy to Setup. 🔥","archived":false,"fork":false,"pushed_at":"2025-03-17T11:47:43.000Z","size":21,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-17T12:33:09.146Z","etag":null,"topics":["authentication","easy","jwt","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itsmeadarsh2008.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"itsmeadarsh2008","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":"itsmeadarsh","thanks_dev":null,"custom":null}},"created_at":"2025-03-17T10:13:05.000Z","updated_at":"2025-03-17T11:51:20.000Z","dependencies_parsed_at":"2025-03-17T12:44:12.520Z","dependency_job_id":null,"html_url":"https://github.com/itsmeadarsh2008/haze","commit_stats":null,"previous_names":["itsmeadarsh2008/haze"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmeadarsh2008%2Fhaze","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmeadarsh2008%2Fhaze/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmeadarsh2008%2Fhaze/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itsmeadarsh2008%2Fhaze/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itsmeadarsh2008","download_url":"https://codeload.github.com/itsmeadarsh2008/haze/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246274308,"owners_count":20751044,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","easy","jwt","python"],"created_at":"2025-03-30T04:19:59.567Z","updated_at":"2025-03-30T04:20:00.053Z","avatar_url":"https://github.com/itsmeadarsh2008.png","language":"Python","funding_links":["https://github.com/sponsors/itsmeadarsh2008","https://buymeacoffee.com/itsmeadarsh"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"https://gist.githubusercontent.com/itsmeadarsh2008/a8b8598c207f00e2795238012d2c5e61/raw/2eeff30b77fff86c12e1a01a60016f0b5d709216/haze.svg\" width=\"200\" height=\"200\"\u003e\n\u003ch1\u003eHaze - Lightning-Fast Magic Link Authentication\u003c/h1\u003e\n\u003cimg alt=\"PyPI - Downloads\" src=\"https://img.shields.io/pypi/dm/haze-auth\"\u003e\n\u003cimg alt=\"GitHub Sponsors\" src=\"https://img.shields.io/github/sponsors/itsmeadarsh2008\"\u003e\n\u003cimg alt=\"PyPI - Python Version\" src=\"https://img.shields.io/pypi/pyversions/haze-auth\"\u003e\n\u003cimg alt=\"PyPI - Version\" src=\"https://img.shields.io/pypi/v/haze-auth\"\u003e\n\u003cimg alt=\"Star\" src=\"https://img.shields.io/badge/Please%20Give%20A%20Star%20%E2%AD%90-30323D\"\u003e\n\u003c/div\u003e\n\nHaze is a high-performance, easy-to-use Magic Link Authentication service for Python applications. Generate secure authentication links that work across devices with minimal setup.\n\n## Features\n\n- ⚡ **Fast \u0026 Efficient** - Optimized core with minimal overhead\n- 🔒 **Ultra Secure** - Modern cryptography with JWT\n- 🔧 **Highly Configurable** - Like Neovim, but for authentication\n- 🧩 **Zero Daemon** - No background processes required\n- 📦 **Minimal Dependencies** - Lightweight core with optional extras\n- 📱 **Cross-Device Auth** - Click on phone, authenticate on desktop\n- 💾 **Pluggable Storage** - Use any database system\n- 🦄 **Modern Defaults** - NanoID, JWT, MsgPack by default\n\n## Installation\n\nSince Haze is now available on PYPI, you can use any package manager you want.\n\n```bash\npip install haze-auth[full]\n\n# Basic installation (install jwt later, with different package version)\npip install git+https://github.com/itsmeadarsh2008/haze.git@main\n\n# With JWT support (Recommended)\npip install \"haze[jwt] @ git+https://github.com/itsmeadarsh2008/haze.git@main\"\n\n# With all optional dependencies\npip install \"haze [full] @ git+https://github.com/itsmeadarsh2008/haze.git@main\"\n```\n\nYou can also specify individual extra dependencies:\n\n```bash\n# Pick and choose what you need\npip install \"haze[\u003coptional deps\u003e] git+https://github.com/itsmeadarsh2008/haze.git\"\n```\n\n## Quick Start\n\n```python\nimport haze\nimport secrets\n\n# Configure Haze\nhaze.use(\n    base_url=\"https://myapp.com\",\n    magic_link_path=\"/auth/verify\",\n    secret_key=secrets.token_urlsafe(32)\n)\n\n# Simple in-memory storage for demo purposes\ntoken_store = {}\n\n# Define storage handler\n@haze.storage\ndef store_token(token_id, data=None):\n    if data is None:\n        return token_store.get(token_id)\n    token_store[token_id] = data\n    return data\n\n# Generate a magic link for a user\nlink = haze.generate(\n    user_id=\"user123\",\n    metadata={\"name\": \"John Doe\", \"email\": \"john@example.com\"}\n)\nprint(f\"Magic Link: {link}\")\n\n# Verify the magic link\n# This is typically done in your web endpoint\n@app.route(\"/auth/verify\")\ndef verify_link():\n    token_id = request.args.get(\"token_id\")\n    signature = request.args.get(\"signature\")\n\n    try:\n        user_data = haze.verify(token_id, signature)\n        # Authentication successful\n        # Set session, JWT, etc.\n        return {\"success\": True, \"user\": user_data}\n    except Exception as e:\n        return {\"success\": False, \"error\": str(e)}\n```\n\n## Advanced Usage\n\n### Custom Configuration\n\n```python\nhaze.use(\n    # Base settings\n    base_url=\"https://myapp.com\",\n    magic_link_path=\"/auth/magic\",\n    link_expiry=3600,  # 1 hour\n    allow_reuse=False,  # One-time use by default\n\n    # Token settings\n    token_provider=\"jwt\",\n    jwt_algorithm=\"HS256\",  # or RS256, ES256\n    \n    # ID generation\n    id_generator=\"nanoid\",  # or \"uuid\"\n    nanoid_size=21,\n\n    # Format settings\n    serialization_format=\"msgpack\"  # or \"json\"\n)\n```\n\n### Using with JWT\n\n```python\nimport secrets\n\n# Generate a secure key\nsecret_key = secrets.token_urlsafe(32)\n\n# Configure Haze to use JWT with HMAC\nhaze.use(\n    token_provider=\"jwt\",\n    jwt_algorithm=\"HS256\",\n    secret_key=secret_key\n)\n```\n\n### Using with Asymmetric Keys (JWT)\n\n```python\nfrom cryptography.hazmat.primitives.asymmetric import rsa\nfrom cryptography.hazmat.primitives import serialization\n\n# Generate key pair\nprivate_key = rsa.generate_private_key(\n    public_exponent=65537,\n    key_size=2048\n)\npublic_key = private_key.public_key()\n\n# Configure Haze\nhaze.use(\n    token_provider=\"jwt\",\n    jwt_algorithm=\"RS256\",\n    private_key=private_key,\n    public_key=public_key\n)\n```\n\n### Database Integration Examples\n\n#### With SQLAlchemy\n\n```python\nfrom sqlalchemy import create_engine, Column, String, Integer, Boolean, JSON, Text\nfrom sqlalchemy.ext.declarative import declarative_base\nfrom sqlalchemy.orm import sessionmaker\n\n# Setup database\nBase = declarative_base()\nengine = create_engine(\"sqlite:///haze_tokens.db\")\nSession = sessionmaker(bind=engine)\n\nclass Token(Base):\n    __tablename__ = \"tokens\"\n\n    token_id = Column(String, primary_key=True)\n    user_id = Column(String, nullable=False)\n    exp = Column(Integer, nullable=False)\n    created_at = Column(Integer, nullable=False)\n    metadata = Column(JSON, nullable=True)\n    consumed = Column(Boolean, default=False)\n\nBase.metadata.create_all(engine)\n\n# Setup Haze storage handler\n@haze.storage\ndef store_token(token_id, data=None):\n    session = Session()\n    try:\n        if data is None:\n            # Retrieve token\n            token = session.query(Token).filter_by(token_id=token_id).first()\n            if not token:\n                return None\n            return {\n                \"user_id\": token.user_id,\n                \"exp\": token.exp,\n                \"created_at\": token.created_at,\n                \"metadata\": token.metadata,\n                \"consumed\": token.consumed\n            }\n        else:\n            # Create or update token\n            token = session.query(Token).filter_by(token_id=token_id).first()\n            if token:\n                # Update existing token\n                token.user_id = data[\"user_id\"]\n                token.exp = data[\"exp\"]\n                token.created_at = data.get(\"created_at\")\n                token.metadata = data.get(\"metadata\")\n                token.consumed = data.get(\"consumed\", False)\n            else:\n                # Create new token\n                token = Token(\n                    token_id=token_id,\n                    user_id=data[\"user_id\"],\n                    exp=data[\"exp\"],\n                    created_at=data.get(\"created_at\"),\n                    metadata=data.get(\"metadata\"),\n                    consumed=data.get(\"consumed\", False)\n                )\n                session.add(token)\n\n            session.commit()\n            return data\n    finally:\n        session.close()\n```\n\n#### With Redis\n\n```python\nimport redis\nimport json\nimport time\n\n# Setup Redis connection\nr = redis.Redis(host='localhost', port=6379, db=0)\n\n@haze.storage\ndef store_token(token_id, data=None):\n    key = f\"haze:token:{token_id}\"\n    if data is None:\n        # Retrieve token\n        token_data = r.get(key)\n        if not token_data:\n            return None\n        return json.loads(token_data)\n    else:\n        # Store token with expiration\n        ttl = data[\"exp\"] - int(time.time())\n        r.setex(key, ttl, json.dumps(data))\n        return data\n```\n\n### Event Handlers\n\nHaze provides hooks for various authentication events:\n\n```python\n# Called when a link is verified\n@haze.verification\ndef on_verification(user_id, token_data):\n    print(f\"User {user_id} verified with token: {token_data['jti']}\")\n    # Update last login time, etc.\n\n# Called when a magic link is clicked\n@haze.onclick\ndef on_link_clicked(user_id, user_data):\n    print(f\"User {user_id} clicked magic link\")\n    # Track analytics, etc.\n```\n\n### Using with Popular Web Frameworks\n\n#### Flask Example\n\n```python\nfrom flask import Flask, request, redirect, session\nimport haze\nimport secrets\n\napp = Flask(__name__)\napp.secret_key = secrets.token_urlsafe(32)\n\n# Configure Haze\nhaze.use(\n    base_url=\"http://localhost:5000\",  # For local development\n    magic_link_path=\"/auth/verify\",\n    secret_key=app.secret_key\n)\n\n# Simple in-memory storage for demo purposes\ntoken_store = {}\n\n@haze.storage\ndef store_token(token_id, data=None):\n    if data is None:\n        return token_store.get(token_id)\n    token_store[token_id] = data\n    return data\n\n@app.route(\"/login\", methods=[\"POST\"])\ndef login():\n    email = request.form.get(\"email\")\n    if not email:\n        return {\"error\": \"Email required\"}, 400\n\n    # Generate magic link\n    link = haze.generate(\n        user_id=email,\n        metadata={\"email\": email}\n    )\n\n    # In a real app, send this link via email\n    # For demo, we'll just return it\n    return {\"link\": link}\n\n@app.route(\"/auth/verify\")\ndef verify():\n    token_id = request.args.get(\"token_id\")\n    signature = request.args.get(\"signature\")\n\n    try:\n        user_data = haze.verify(token_id, signature)\n        # Set session\n        session[\"user_id\"] = user_data[\"user_id\"]\n        session[\"authenticated\"] = True\n\n        # Redirect to dashboard\n        return redirect(\"/dashboard\")\n    except Exception as e:\n        return {\"error\": str(e)}, 400\n\n@app.route(\"/dashboard\")\ndef dashboard():\n    if not session.get(\"authenticated\"):\n        return redirect(\"/login\")\n\n    return f\"Welcome, {session.get('user_id')}!\"\n```\n\n#### FastAPI Example\n\n```python\nfrom fastapi import FastAPI, Depends, HTTPException, Request, Response\nfrom fastapi.responses import RedirectResponse\nfrom pydantic import BaseModel, EmailStr\nimport secrets\nimport haze\n\napp = FastAPI()\n\n# Configure Haze\nhaze.use(\n    base_url=\"http://localhost:8000\",  # For local development\n    magic_link_path=\"/auth/verify\",\n    secret_key=secrets.token_urlsafe(32)\n)\n\n# Simple in-memory storage\ntoken_store = {}\n\n@haze.storage\ndef store_token(token_id, data=None):\n    if data is None:\n        return token_store.get(token_id)\n    token_store[token_id] = data\n    return data\n\nclass LoginRequest(BaseModel):\n    email: EmailStr\n\n@app.post(\"/login\")\nasync def login(request: LoginRequest):\n    # Generate magic link\n    link = haze.generate(\n        user_id=request.email,\n        metadata={\"email\": request.email}\n    )\n\n    # In a real app, send this link via email\n    return {\"link\": link}\n\n@app.get(\"/auth/verify\")\nasync def verify(token_id: str, signature: str, response: Response):\n    try:\n        user_data = haze.verify(token_id, signature)\n\n        # Set cookie for authentication\n        response.set_cookie(\n            key=\"session_token\",\n            value=user_data[\"user_id\"],\n            httponly=True,\n            secure=False,  # Set to True in production with HTTPS\n            samesite=\"lax\"\n        )\n\n        return RedirectResponse(url=\"/dashboard\")\n    except Exception as e:\n        raise HTTPException(status_code=400, detail=str(e))\n\n@app.get(\"/dashboard\")\nasync def dashboard(request: Request):\n    session_token = request.cookies.get(\"session_token\")\n    if not session_token:\n        return RedirectResponse(url=\"/login\")\n\n    return {\"message\": f\"Welcome, {session_token}!\"}\n```\n\n## Security Best Practices\n\n1. **Always use HTTPS** for production environments\n2. **Set appropriate token expiry times** - shorter is better\n3. **Rotate your secret keys periodically**\n4. **Use asymmetric cryptography** (JWT with RSA/ECDSA) for increased security\n5. **Implement rate limiting** to prevent brute force attacks\n6. **Store tokens securely** in a database with proper encryption\n7. **Enable one-time use** for magic links by setting `allow_reuse=False`\n\n## Troubleshooting\n\n### Common Issues\n\n#### \"ModuleNotFoundError\" for optional dependencies\n\n```bash\npip install \"haze[full] @ git+https://github.com/itsmeadarsh2008/haze.git\"\n```\n\n#### \"ConfigurationError: secret_key must be set\"\n\nEnsure you've set a secure secret key with `haze.use(secret_key=...)`.\n\n#### \"ValidationError: Token expired\"\n\nThe magic link has expired. Generate a new one or increase the `link_expiry` setting.\n\n#### \"ValidationError: Token not found\"\n\nThe token doesn't exist in storage. Check your storage handler implementation.\n\n#### \"ValidationError: Invalid signature\"\n\nThe signature verification failed. This could indicate a tampered link or configuration issues.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmeadarsh2008%2Fhaze","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitsmeadarsh2008%2Fhaze","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitsmeadarsh2008%2Fhaze/lists"}