Blog

  • Python Server-Sent Events Sse Web App

    When you need real‑time updates without the overhead of WebSockets, Server‑Sent Events (SSE) offer a lightweight, browser‑native solution that works perfectly with Python web frameworks. In this guide we’ll explore what SSE is, why it’s a great fit for Python web apps, and walk through building a complete SSE‑powered application using Flask (the concepts apply equally to Django, FastAPI, and other frameworks). By the end you’ll have a production‑ready codebase, SEO‑friendly content, and a solid understanding of how to scale SSE in the Python ecosystem.

    What Are Server‑Sent Events?

    Server‑Sent Events, standardized in the HTML5 EventSource API, allow a server to push a stream of text‑based messages to the browser over a single HTTP connection. Unlike WebSockets, SSE is unidirectional (server → client) and automatically handles reconnection, making it ideal for:

    • Live dashboards and analytics
    • Chat notifications and typing indicators
    • Stock tickers, sports scores, or any frequently updating data
    • Background task progress bars

    Because SSE uses plain HTTP, it works seamlessly with proxies, load balancers, and CDNs, and it benefits from built‑in browser support for automatic reconnection and event ID tracking.

    Why Choose Python for SSE?

    Python’s rich ecosystem of asynchronous libraries and lightweight web frameworks makes it a natural fit for SSE. Here are a few reasons to consider Python when building an SSE web app:

    • Readability: Python’s clear syntax speeds up development and maintenance.
    • Async support: Modern frameworks like FastAPI and Starlette provide native async capabilities, crucial for handling many concurrent connections.
    • Extensive libraries: Packages such as Flask‑SSE, django-sse, and aiohttp simplify boilerplate code.
    • Scalability: With tools like uvicorn, gunicorn, and Redis pub/sub, you can scale SSE to thousands of clients.

    Core Concepts of an SSE Endpoint

    Content Type and HTTP Headers

    An SSE endpoint must return the Content-Type: text/event-stream header and keep the connection open. The server streams data in the following format:

    event: message
    id: 42
    data: {"value": 123}
    

    Each field ends with a newline, and a double newline signals the end of a message.

    Automatic Reconnection

    The browser automatically attempts to reconnect if the connection drops. You can control the retry interval with the retry field:

    retry: 3000
    

    This tells the client to wait 3 seconds before reconnecting.

    Building a Simple SSE App with Flask

    Below is a step‑by‑step example of a minimal Flask application that broadcasts random numbers to connected browsers every second. The same logic can be adapted to Django, FastAPI, or any ASGI‑compatible framework.

    1. Install Required Packages

    pip install Flask Flask-SSE redis
    

    We’ll use redis as a lightweight message broker, but for a single‑process demo you can skip it.

    2. Project Structure

    my_sse_app/
    │
    ├─ app.py
    ├─ templates/
    │   └─ index.html
    └─ requirements.txt
    

    3. Server Code (app.py)

    from flask import Flask, render_template, request
    from flask_sse import sse
    import random
    import time
    import threading
    
    app = Flask(__name__)
    
    # Configure Redis (default localhost:6379)
    app.config["REDIS_URL"] = "redis://localhost"
    app.register_blueprint(sse, url_prefix='/stream')
    
    @app.route('/')
    def index():
        return render_template('index.html')
    
    def generate_numbers():
        """Background thread that publishes a new number every second."""
        while True:
            number = random.randint(1, 100)
            sse.publish({"value": number}, type='number')
            time.sleep(1)
    
    # Start background thread only once
    thread = threading.Thread(target=generate_numbers)
    thread.daemon = True
    thread.start()
    
    if __name__ == '__main__':
        # Use a production-ready server in real deployments
        app.run(debug=True, threaded=True)
    

    4. Client‑Side HTML (templates/index.html)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Python SSE Demo</title>
        <style>
            body {font-family: Arial, sans-serif; margin: 2rem;}
            #log {border: 1px solid #ccc; padding: 1rem; height: 300px; overflow-y: auto;}
        </style>
    </head>
    <body>
        <h2>Live Random Numbers (Server‑Sent Events)</h2>
        <div id="log"></div>
    
        <script>
            const log = document.getElementById('log');
            const source = new EventSource('/stream');
    
            source.addEventListener('number', function(event) {
                const data = JSON.parse(event.data);
                const entry = document.createElement('div');
                entry.textContent = `Received: ${data.value}`;
                log.appendChild(entry);
                log.scrollTop = log.scrollHeight;
            });
    
            source.onerror = function(err) {
                console.error('SSE error', err);
                source.close();
            };
        </script>
    </body>
    </html>
    

    5. Run the App

    python app.py
    

    Open http://localhost:5000 in a browser and watch a new random number appear every second without refreshing the page.

    Scaling SSE in Production

    While the example above works for development, production environments require a few extra considerations to handle high traffic and ensure reliability.

    Use an ASGI Server

    Flask’s built‑in server is single‑threaded and not suitable for many concurrent connections. Deploy with gunicorn + uvicorn workers or switch to an ASGI‑native framework like FastAPI:

    gunicorn -k uvicorn.workers.UvicornWorker app:app --workers 4
    

    Leverage a Message Broker

    • Redis Pub/Sub: Publish events from any process; all workers receive them.
    • RabbitMQ or Kafka: For enterprise‑grade durability and replay capabilities.

    Load Balancer Configuration

    Because SSE relies on a persistent HTTP connection, make sure your load balancer (NGINX, HAProxy, AWS ELB) is configured to:

    • Disable HTTP/2 push for SSE streams.
    • Set a high proxy_read_timeout (e.g., 300s) to keep connections alive.
    • Enable sticky sessions if you’re not using a shared message broker.

    Graceful Shutdown & Heartbeats

    Long‑living connections can be terminated by network devices. Sending a comment line (:) every 15–30 seconds acts as a heartbeat:

    def sse_heartbeat():
        while True:
            sse.publish({}, type='heartbeat')
            time.sleep(20)
    

    Clients can ignore heartbeat events or use them to detect connection health.

    Advanced Features and Best Practices

    Custom Event Types

    Instead of the default message event, you can define meaningful names (e.g., chat, notification) to simplify client‑side handling.

    Event IDs for Reliable Delivery

    Including an id field lets the browser request missed events after a reconnection:

    sse.publish({"value": 42}, type='number', id=str(uuid4()))
    

    Combine this with a server‑side store (Redis list, database) to replay missed messages.

    Security Considerations

    • CORS: Set Access-Control-Allow-Origin only for trusted origins.
    • Authentication: Use session cookies or JWT tokens; verify them before establishing the SSE stream.
    • Rate Limiting: Prevent a single client from opening hundreds of SSE connections.

    Testing SSE Endpoints

    Automated tests can be written with pytest and httpx (async) or requests for simple cases. Example using httpx:

    import httpx
    import asyncio

    async def test_sse():
    async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
    async with client.stream("GET", "/stream") as response:
    async for line in response.aiter_lines():
    if line.startswith("data:"):

  • Python Https Local Development Setup

    Developing web applications with Python often requires testing secure connections early in the development cycle. Running an HTTPS server locally not only mirrors production environments but also helps catch mixed‑content warnings, cookie‑security issues, and OAuth redirects before they reach users. In this guide you’ll learn how to set up a fully functional HTTPS development environment on your own machine, using only open‑source tools, self‑signed certificates, and a few handy Python utilities.

    Why Use HTTPS in Local Development?

    Even though browsers will happily load http://localhost, modern web standards and many third‑party services demand https for:

    • Secure cookies – the Secure flag is ignored on plain HTTP.
    • Content Security Policy (CSP) – mixed‑content violations are blocked.
    • OAuth / OpenID Connect – most providers require a HTTPS redirect URI.
    • Service workers – they only run on secure origins.

    By configuring HTTPS locally, you eliminate a whole class of bugs that only appear after deployment.

    Prerequisites

    Before diving into the setup, make sure you have the following installed on your development machine:

    • Python 3.8+ (the venv module is used for isolation)
    • pip – the Python package manager
    • OpenSSL (usually pre‑installed on macOS/Linux; Windows users can get it via Win64 OpenSSL)
    • A code editor or IDE of your choice

    Step‑by‑Step HTTPS Setup

    1. Create a Python Virtual Environment

    python -m venv .venv
    source .venv/bin/activate   # macOS/Linux
    .\.venv\Scripts\activate    # Windows PowerShell
    

    Using a virtual environment keeps your development dependencies isolated from the global Python installation.

    2. Install Required Packages

    For this tutorial we’ll use Flask as the web framework, but the same certificate can be reused with Django, FastAPI, or any WSGI server.

    pip install Flask Werkzeug
    

    3. Generate a Self‑Signed Certificate

    OpenSSL can create a certificate and private key in a single command. Run the following in your project root:

    openssl req -x509 -newkey rsa:2048 -nodes -keyout localhost.key \
      -out localhost.crt -days 365 \
      -subj "/C=US/ST=California/L=San Francisco/O=MyCompany/OU=Dev/CN=localhost"
    

    This generates two files:

    • localhost.key – the private key (keep it secret)
    • localhost.crt – the public certificate that browsers will trust after you add an exception

    4. Trust the Certificate (Optional but Recommended)

    Most browsers will show a warning for self‑signed certificates. To silence the warning you can add the certificate to your OS trust store:

    • macOS: double‑click localhost.crt and add it to the “System” keychain, then set it to “Always Trust”.
    • Linux (Ubuntu/Debian): sudo cp localhost.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates
    • Windows: run certmgr.msc, import the certificate into “Trusted Root Certification Authorities”.

    After trusting, browsers will treat https://localhost as a secure origin.

    5. Write a Minimal Flask App with HTTPS

    from flask import Flask, jsonify
    
    app = Flask(__name__)
    
    @app.route('/api/hello')
    def hello():
        return jsonify(message='Hello, secure world!')
    
    if __name__ == '__main__':
        # Enable reloader and debugger for development only
        app.run(host='127.0.0.1', port=5000, debug=True,
                ssl_context=('localhost.crt', 'localhost.key'))
    

    Running this script starts a development server listening on https://127.0.0.1:5000. The ssl_context tuple tells Flask to use the certificate we created.

    6. Test the Secure Endpoint

    Open a browser and navigate to https://127.0.0.1:5000/api/hello. You should see a JSON response similar to:

    {
      "message": "Hello, secure world!"
    }
    

    If you added the certificate to the trust store, the address bar will display a lock icon, confirming that the connection is truly encrypted.

    Advanced Configurations

    Using a Reverse Proxy (Nginx) for More Realistic Scenarios

    Production environments often sit behind a reverse proxy that terminates TLS. Replicating this locally helps you catch proxy‑related issues early.

    1. Install Nginx (e.g., brew install nginx on macOS or sudo apt-get install nginx on Ubuntu).
    2. Create a new site configuration, /etc/nginx/sites-available/pydev:
    server {
        listen 443 ssl;
        server_name localhost;
    
        ssl_certificate     /path/to/localhost.crt;
        ssl_certificate_key /path/to/localhost.key;
    
        location / {
            proxy_pass http://127.0.0.1:5000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
    

    Enable the site and reload Nginx:

    sudo ln -s /etc/nginx/sites-available/pydev /etc/nginx/sites-enabled/
    sudo nginx -t && sudo systemctl reload nginx
    

    Now access your app via https://localhost (port 443). Nginx handles TLS, while Flask runs unencrypted on the internal port.

    Hot‑Reloading with HTTPS in Django

    If you prefer Django, the built‑in runserver command supports TLS from version 4.0 onward:

    python manage.py runserver_plus --cert-file localhost.crt --key-file localhost.key
    

    Alternatively, use django-extensions which ships the runserver_plus command out of the box.

    Automating Certificate Generation with a Makefile

    To avoid manually re‑creating certificates each time you clone the repo, add a simple Make target:

    .PHONY: cert
    cert:
    \t@openssl req -x509 -newkey rsa:2048 -nodes -keyout localhost.key \
    \t\t-out localhost.crt -days 365 \
    \t\t-subj "/C=US/ST=CA/L=SF/O=MyCompany/OU=Dev/CN=localhost"
    

    Now running make cert instantly produces a fresh pair.

    Common Pitfalls & How to Fix Them

    Browser Still Shows “Not Secure”

    • Certificate not trusted: Ensure you imported the .crt into the correct trust store.
    • Wrong hostname: The CN (Common Name) must match the URL you use (e.g., localhost or 127.0.0.1).
    • Mixed content: Verify that all assets (CSS, JS, images) are loaded over https:// as well.

    SSL Handshake Errors in API Clients

    Tools like curl or Postman may reject self‑signed certificates by default. Use the -k flag with curl or disable SSL verification in Postman for local testing.

    Port Conflicts

    If port 443 is already in use (common on macOS with AirPlay), change the Nginx listen directive to an unused port, e.g., listen 8443 ssl;, and update your browser URL accordingly.

    SEO Benefits of Developing with HTTPS

    Search engines like Google treat HTTPS as a ranking signal. While local development doesn’t directly affect SEO, building and testing with HTTPS ensures that:

    • All internal links use https://, preventing accidental canonical mismatches.
    • Structured data scripts are delivered securely, avoiding “mixed‑content” penalties.
    • Performance metrics (e.g., Largest Contentful Paint) are measured under realistic network conditions, helping you meet Core Web Vitals.

    When you ship the same HTTPS configuration to production, you avoid a costly “HTTPS migration” phase and keep your SEO juice intact.

    Testing Tools for Your Secure Local Server

    After the setup, you’ll want to verify that everything works as expected. Here are a few quick tools:

  • Python Web Security Best Practices Guide

    When you build a Python web application, security isn’t an after‑thought—it’s a foundational requirement. From data breaches to malicious code injection, the stakes are high, and the Python ecosystem offers powerful tools to keep your site safe—if you know how to use them. In this guide we’ll walk through the most effective Python web security best practices, covering everything from input validation to secure framework configuration, so you can protect your users, your data, and your reputation.

    Understanding the Threat Landscape

    Before diving into code, it’s essential to know what you’re defending against. Common attacks on Python web apps include:

    • SQL injection – malicious input that manipulates database queries.
    • Cross‑site scripting (XSS) – injecting scripts into pages viewed by other users.
    • Cross‑site request forgery (CSRF) – tricking a logged‑in user into performing unwanted actions.
    • Remote code execution (RCE) – exploiting unsafe deserialization or unsafe system calls.
    • Insecure deserialization – loading untrusted data into Python objects.

    By recognizing these vectors early, you can apply targeted defenses throughout the development lifecycle.

    Secure Coding Practices

    Input Validation and Sanitization

    Never trust user input. Validate data types, length, format, and range before processing.

    import re
    
    def is_valid_email(email: str) -> bool:
        pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
        return re.match(pattern, email) is not None
    

    Use is_valid_email in forms, APIs, and CLI tools to reject malformed addresses before they reach your database.

    Use of Prepared Statements

    Parameterized queries eliminate the risk of SQL injection by separating code from data.

    from sqlalchemy import text
    from myapp import db
    
    def get_user_by_email(email: str):
        stmt = text("SELECT * FROM users WHERE email = :email")
        return db.session.execute(stmt, {"email": email}).fetchone()
    

    Proper Error Handling

    Expose only necessary information in error messages. Detailed stack traces are valuable for developers, but they can reveal internals to attackers.

    • Log full errors to a secure file or monitoring service.
    • Return generic messages to the client, e.g., Invalid credentials instead of Database connection failed.

    Authentication and Authorization

    Strong Password Policies

    Enforce complexity, length, and rotation rules. Store passwords with a modern hashing algorithm such as argon2 or bcrypt.

    from passlib.hash import argon2
    
    def hash_password(pwd: str) -> str:
        return argon2.hash(pwd)
    
    def verify_password(pwd: str, hashed: str) -> bool:
        return argon2.verify(pwd, hashed)
    

    Multi‑Factor Authentication (MFA)

    Adding a second factor dramatically reduces credential‑theft risk. Popular Python libraries for TOTP include pyotp and django-otp.

    import pyotp
    
    def generate_totp(secret: str) -> str:
        totp = pyotp.TOTP(secret)
        return totp.now()
    

    Session Management

    • Mark cookies as HttpOnly and Secure.
    • Use SameSite=Lax or Strict to mitigate CSRF.
    • Rotate session identifiers after login and periodically during a session.

    In Django, enable these settings in settings.py:

    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = True
    CSRF_COOKIE_SAMESITE = 'Lax'
    

    Protecting Data in Transit and at Rest

    TLS/SSL Everywhere

    All external traffic must be encrypted with TLS 1.2 or higher. Use automated certificate management tools like Let’s Encrypt and enforce HTTPS with HSTS.

    # Example Flask configuration
    app.config.update(
        PREFERRED_URL_SCHEME='https',
        SESSION_COOKIE_SECURE=True,
        REMEMBER_COOKIE_SECURE=True,
    )
    

    Encryption of Sensitive Data

    Never store raw credit‑card numbers, social security numbers, or personal health information. Use field‑level encryption when data must be persisted.

    from cryptography.fernet import Fernet
    
    key = Fernet.generate_key()
    cipher = Fernet(key)
    
    def encrypt(value: str) -> bytes:
        return cipher.encrypt(value.encode())
    
    def decrypt(token: bytes) -> str:
        return cipher.decrypt(token).decode()
    

    Secure Configuration of Frameworks

    Django Security Settings

    • DEBUG = False in production.
    • Set ALLOWED_HOSTS to a whitelist of domains.
    • Enable SECURE_CONTENT_TYPE_NOSNIFF and SECURE_BROWSER_XSS_FILTER.
    • Use django.middleware.security.SecurityMiddleware to enforce HSTS.
    # settings.py excerpt
    DEBUG = False
    ALLOWED_HOSTS = ['example.com', 'www.example.com']
    SECURE_HSTS_SECONDS = 31536000  # 1 year
    SECURE_HSTS_INCLUDE_SUBDOMAINS = True
    SECURE_HSTS_PRELOAD = True
    

    Flask Security Tips

    • Leverage Flask-Talisman for security headers.
    • Use Flask-Limiter to protect against brute‑force attacks.
    • Never expose the secret key; load it from environment variables or a vault.
    from flask import Flask
    from flask_talisman import Talisman
    from flask_limiter import Limiter
    from flask_limiter.util import get_remote_address
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY')
    Talisman(app, content_security_policy=None)
    limiter = Limiter(app, key_func=get_remote_address)
    
    @limiter.limit("5 per minute")
    @app.route('/login', methods=['POST'])
    def login():
        # login logic here
        pass
    

    Dependency Management and Patch Management

    Third‑party libraries are a frequent source of vulnerabilities. Follow these practices:

    1. Pin exact versions in requirements.txt or poetry.lock.
    2. Run pip list --outdated regularly and apply security patches promptly.
    3. Integrate automated scanning tools such as Snyk, Dependabot, or Bandit into your CI/CD pipeline.
    4. Prefer well‑maintained packages with active security response teams.

    Logging, Monitoring, and Incident Response

    A robust security posture includes visibility into what’s happening in real time.

    • Log authentication events, permission changes, and error codes at INFO or higher.
    • Never log passwords, tokens, or personal data.
    • Send logs to a centralized, tamper‑proof system (e.g., ELK stack, Splunk, or CloudWatch).
    • Set up alerts for suspicious patterns: multiple failed logins, unusual IP locations, or sudden spikes in request volume.

    Prepare an incident response plan that defines roles, communication channels, and steps for containment, eradication, and post‑mortem analysis.

    Conclusion

    Securing a Python web application is a continuous journey that blends disciplined coding, proper framework configuration, vigilant dependency management, and proactive monitoring. By implementing the best practices outlined above—validating input, using prepared statements, enforcing strong authentication, encrypting data, and keeping your stack up to date—you’ll dramatically reduce the attack surface of your app. Remember, security is not a single feature; it’s an integral part of the development lifecycle that protects your users and your brand. Start applying these guidelines today, and stay ahead of the ever‑evolving threat landscape.

  • Python Multi-Factor Authentication Mfa Setup

    In today’s security‑first landscape, Python multi-factor authentication (MFA) setup is no longer a nice‑to‑have feature—it’s a critical requirement for protecting user data and preventing unauthorized access. Whether you’re building a Flask API, a Django web app, or a simple script, adding MFA can dramatically reduce the risk of credential‑stuffing attacks and boost user confidence. In this guide we’ll walk through the concepts, choose the right Python libraries, and provide a step‑by‑step, code‑first tutorial that you can copy‑paste into your own project.

    Why Multi‑Factor Authentication Matters for Python Applications

    Traditional username‑and‑password authentication relies on a single secret that can be compromised through phishing, data breaches, or weak password choices. MFA adds one or more independent verification steps, typically something you have (a mobile device or hardware token) or something you are (biometrics). The benefits are clear:

    • Reduced attack surface: Even if a password is leaked, an attacker still needs the second factor.
    • Regulatory compliance: Standards such as GDPR, HIPAA, and PCI‑DSS often require MFA for sensitive operations.
    • Improved user trust: Users feel safer knowing their accounts are protected by more than just a password.

    Choosing the Right Python MFA Library

    Python’s ecosystem offers several mature libraries for implementing MFA. Below is a quick comparison to help you decide which tool fits your stack:

    • PyOTP – Simple Time‑Based One‑Time Password (TOTP) and HMAC‑Based OTP (HOTP) generation. Ideal for integrating Google Authenticator or Authy.
    • python-fido2 – Full support for FIDO2/WebAuthn hardware keys (YubiKey, SoloKey). Great for password‑less flows.
    • django-otp – Plug‑and‑play OTP support for Django projects, with built‑in models and views.
    • Flask‑User / Flask‑Security‑Too – Extensions that add MFA capabilities on top of Flask authentication.

    Step‑by‑Step MFA Setup Using PyOTP and Flask

    Prerequisites

    • Python 3.9+ installed
    • Virtual environment (venv) activated
    • Flask 2.x installed (`pip install flask`)
    • PyOTP installed (`pip install pyotp`)

    1. Generate and Store a Secret Key

    The secret key is the shared secret between the server and the user’s authenticator app. It must be stored securely—typically encrypted in the database.

    import pyotp
    import os
    import base64
    
    def generate_secret():
        # 32‑byte base32 secret, compatible with Google Authenticator
        return pyotp.random_base32()
    
    # Example usage
    user_secret = generate_secret()
    print(f"User secret (store securely): {user_secret}")
    

    2. Create a QR Code for Easy Enrollment

    Most users prefer scanning a QR code rather than typing the secret manually. The qrcode library works well with Flask.

    import qrcode
    from io import BytesIO
    import base64
    
    def get_qr_code_uri(username, issuer, secret):
        # Build the otpauth URI
        return pyotp.totp.TOTP(secret).provisioning_uri(name=username, issuer_name=issuer)
    
    def generate_qr_image(uri):
        img = qrcode.make(uri)
        buffer = BytesIO()
        img.save(buffer, format="PNG")
        return base64.b64encode(buffer.getvalue()).decode()
    
    # Example
    uri = get_qr_code_uri("alice@example.com", "MyFlaskApp", user_secret)
    qr_base64 = generate_qr_image(uri)
    print(f"Data URI for HTML: data:image/png;base64,{qr_base64}")
    

    Render the qr_base64 string in an <img> tag on the enrollment page.

    3. Verify the OTP Provided by the User

    When the user logs in, prompt for the 6‑digit code generated by their authenticator app and validate it against the stored secret.

    def verify_otp(secret, token):
        totp = pyotp.TOTP(secret)
        return totp.verify(token, valid_window=1)  # allow +/- 30 seconds
    
    # Example verification
    user_input = "123456"
    if verify_otp(user_secret, user_input):
        print("MFA success!")
    else:
        print("Invalid code.")
    

    4. Integrate MFA Into Flask Login Flow

    Below is a minimal Flask route that demonstrates a two‑step login: first password, then OTP.

    from flask import Flask, request, session, redirect, url_for, render_template_string
    
    app = Flask(__name__)
    app.secret_key = os.urandom(24)  # Replace with a stable secret in production
    
    # Mock user database
    users = {
        "alice": {"password": "s3cr3t", "mfa_secret": user_secret}
    }
    
    login_template = """
    <form method="post">
      Username: <input name="username"><br>
      Password: <input type="password" name="password"><br>
      <input type="submit" value="Login">
    </form>
    """
    
    otp_template = """
    <p>Enter the 6‑digit code from your authenticator app:</p>
    <form method="post">
      <input name="otp">
      <input type="submit" value="Verify">
    </form>
    """
    
    @app.route("/login", methods=["GET", "POST"])
    def login():
        if request.method == "POST":
            username = request.form["username"]
            password = request.form["password"]
            user = users.get(username)
    
            if user and user["password"] == password:
                session["pre_mfa_user"] = username
                return redirect(url_for("mfa"))
            else:
                return "Invalid credentials", 401
        return render_template_string(login_template)
    
    @app.route("/mfa", methods=["GET", "POST"])
    def mfa():
        username = session.get("pre_mfa_user")
        if not username:
            return redirect(url_for("login"))
    
        if request.method == "POST":
            otp = request.form["otp"]
            secret = users[username]["mfa_secret"]
            if verify_otp(secret, otp):
                session["user"] = username
                session.pop("pre_mfa_user", None)
                return f"Welcome, {username}! MFA passed."
            else:
                return "Invalid OTP", 401
        return render_template_string(otp_template)
    
    if __name__ == "__main__":
        app.run(debug=True)
    

    Beyond TOTP: Adding Hardware Token Support with python‑fido2

    While TOTP works for most use‑cases, some organizations demand stronger, phishing‑resistant authentication. The python-fido2 library enables WebAuthn flows that use hardware security keys or platform authenticators (Windows Hello, Touch ID).

    • Register a credential: Server generates a challenge, the client creates a new public‑key credential, and the server stores the public key.
    • Authenticate: Server sends a challenge, the client signs it with the private key, and the server verifies the signature.

    Implementation details are beyond the scope of this article, but the official python‑fido2 GitHub repo provides a full Flask example that can be combined with the TOTP flow for a hybrid MFA strategy.

    Storing Secrets Securely

    Never store MFA secrets in plain text. Follow these best practices:

    1. Encrypt at rest: Use a library like cryptography to encrypt the secret before writing to the database.
    2. Use a dedicated column: Keep MFA data separate from password hashes to simplify key rotation.
    3. Rotate secrets periodically: Offer users the ability to reset their MFA device, generating a new secret.

    Backup Codes and Recovery Options

    Users can lose access to their authenticator app. Provide a set of one‑time backup codes that can be regenerated from the account settings page. Example generation:

    import secrets
    
    def generate_backup_codes(count=10):
        return [secrets.token_hex(4) for _ in range(count)]
    
    print(generate_backup_codes())
    

    Store these codes hashed (e.g., using bcrypt) and mark them as used after the first successful login.

    Testing Your MFA Implementation

    Automated testing ensures the flow works across browsers and devices. Consider the following strategies:

    • Unit tests: Verify verify_otp works with known secrets and timestamps.
    • Integration tests: Use selenium or Playwright to simulate a user scanning a QR code and entering the generated token.
    • Security audits: Run static analysis tools (Bandit, SonarQube) to catch hard‑coded secrets.

    Common Pitfalls and How to Avoid Them

    • Clock drift: T
  • Python Password Reset Via Email Tutorial

    Implementing a secure Python password reset via email is a must‑have feature for any modern web application. Not only does it improve user experience, but it also protects your platform from unauthorized access. In this tutorial we’ll walk through the entire process—from generating a reset token to sending the email and finally updating the user’s password—using plain Python, Flask, and the smtplib library. By the end of the article you’ll have a production‑ready password‑reset flow that you can drop into any project.

    What Makes a Good Password‑Reset System?

    • Security first: Use cryptographically strong tokens that expire after a short period.
    • Usability: The email should contain a clear call‑to‑action and a single clickable link.
    • Reliability: Handle bounced emails and rate‑limit requests to prevent abuse.
    • Scalability: Store tokens in a way that works for both small apps and large deployments.

    High‑Level Workflow

    1. User clicks “Forgot password?” on the login page.
    2. App asks for the user’s email address.
    3. Server generates a signed, time‑limited token.
    4. Email containing a password‑reset link (with the token) is sent to the user.
    5. User clicks the link, which opens a secure reset form.
    6. Server validates the token, updates the password, and invalidates the token.

    Setting Up the Development Environment

    Before we dive into code, make sure you have the following installed:

    • Python 3.9+ (download here)
    • Flask (pip install flask)
    • itsdangerous (comes with Flask, used for token signing)
    • An SMTP service (Gmail, SendGrid, Mailgun, etc.)

    Project Structure

    password_reset_demo/
    ├── app.py
    ├── config.py
    ├── templates/
    │   ├── forgot_password.html
    │   ├── reset_password.html
    │   └── email_template.html
    └── requirements.txt
    

    Creating a Secure Token with itsdangerous

    The itsdangerous library lets us create a signed token that includes the user’s email and an expiration timestamp. This token can be safely embedded in a URL.

    # config.py
    import os
    
    class Config:
        SECRET_KEY = os.getenv('SECRET_KEY', 'a-very-secret-key')
        SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'another-secret')
        MAIL_SERVER = 'smtp.gmail.com'
        MAIL_PORT = 587
        MAIL_USE_TLS = True
        MAIL_USERNAME = os.getenv('MAIL_USERNAME')
        MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
        MAIL_DEFAULT_SENDER = MAIL_USERNAME
    
    # utils.py
    from itsdangerous import URLSafeTimedSerializer
    from flask import current_app
    
    def generate_reset_token(email):
        serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
        return serializer.dumps(email, salt=current_app.config['SECURITY_PASSWORD_SALT'])
    
    def verify_reset_token(token, expiration=3600):
        serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
        try:
            email = serializer.loads(
                token,
                salt=current_app.config['SECURITY_PASSWORD_SALT'],
                max_age=expiration
            )
        except Exception:
            return None
        return email
    

    Sending the Reset Email

    We’ll use Python’s built‑in smtplib for simplicity, but you can replace it with Flask‑Mail or any third‑party service.

    # mailer.py
    import smtplib
    from email.mime.text import MIMEText
    from flask import url_for, render_template, current_app
    
    def send_reset_email(to_email, token):
        reset_url = url_for('reset_password', token=token, _external=True)
        html_body = render_template('email_template.html', reset_url=reset_url)
    
        msg = MIMEText(html_body, 'html')
        msg['Subject'] = 'Your Password Reset Link'
        msg['From'] = current_app.config['MAIL_DEFAULT_SENDER']
        msg['To'] = to_email
    
        with smtplib.SMTP(current_app.config['MAIL_SERVER'],
                          current_app.config['MAIL_PORT']) as server:
            server.starttls()
            server.login(current_app.config['MAIL_USERNAME'],
                         current_app.config['MAIL_PASSWORD'])
            server.send_message(msg)
    

    Flask Routes: From Request to Reset

    # app.py
    from flask import Flask, render_template, request, flash, redirect, url_for
    from config import Config
    from utils import generate_reset_token, verify_reset_token
    from mailer import send_reset_email
    from werkzeug.security import generate_password_hash, check_password_hash
    
    app = Flask(__name__)
    app.config.from_object(Config)
    
    # In‑memory user store for demo purposes
    USERS = {
        'alice@example.com': {
            'password_hash': generate_password_hash('oldpassword')
        }
    }
    
    @app.route('/forgot', methods=['GET', 'POST'])
    def forgot_password():
        if request.method == 'POST':
            email = request.form['email'].strip().lower()
            if email in USERS:
                token = generate_reset_token(email)
                send_reset_email(email, token)
                flash('A password reset link has been sent to your email.', 'info')
            else:
                flash('If that address exists in our system, you will receive an email.', 'info')
            return redirect(url_for('forgot_password'))
        return render_template('forgot_password.html')
    
    @app.route('/reset/', methods=['GET', 'POST'])
    def reset_password(token):
        email = verify_reset_token(token)
        if not email:
            flash('The reset link is invalid or has expired.', 'danger')
            return redirect(url_for('forgot_password'))
    
        if request.method == 'POST':
            new_password = request.form['password']
            USERS[email]['password_hash'] = generate_password_hash(new_password)
            flash('Your password has been updated!', 'success')
            return redirect(url_for('login'))  # Assume a login route exists
        return render_template('reset_password.html', token=token)
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    HTML Templates (Simplified)

    
    <form method="post">
        <label for="email">Enter your email:</label>
        <input type="email" name="email" id="email" required>
        <button type="submit">Send Reset Link</button>
    </form>
    
    
    <form method="post">
        <label for="password">New password:</label>
        <input type="password" name="password" id="password" required>
        <button type="submit">Update Password</button>
    </form>
    
    
    <h3>Password Reset Request</h3>
    <p>Hi,</p>
    <p>We received a request to reset your password. Click the button below to choose a new password. This link will expire in 1 hour.</p>
    <a href="{{ reset_url }}" style="display:inline-block;padding:10px 20px;background:#0069d9;color:#fff;text-decoration:none;border-radius:5px;">Reset My Password</a>
    <p>If you didn’t request this, you can safely ignore this email.</p>
    

    Best Practices & Security Tips

    • Never store plain‑text passwords. Always hash with werkzeug.security.generate_password_hash or bcrypt.
    • Use HTTPS. The reset link must be served over TLS to prevent token sniffing.
    • Rate limit requests. Limit “forgot password” attempts per IP/email to mitigate brute‑force attacks.
    • Invalidate old tokens. Store a token identifier in the database and mark it used after a successful reset.
    • Short token lifespan. 30‑60 minutes is a good balance between usability and security.

    Testing the Flow Locally

    1. Set environment variables for MAIL_USERNAME and MAIL_PASSWORD.
    2. Run python app.py and navigate to http://127.0.0.1:5000/forgot.
    3. Enter a registered email (e.g., alice@example.com) and check your inbox for the reset link.
    4. Click the link, set a new password, and verify that the hash in the USERS dict changes.

    Deploying to Production

    When you move from a development server to production, keep these items in mind:

    • Replace the in‑memory USERS store with a real database (PostgreSQL, MySQL, etc.).
    • Use a robust email service (SendGrid, Amazon SES) to handle deliverability and bounce tracking.
    • Store SECRET_KEY and SECURITY_PASSWORD_SALT as environment variables, never in source control.
    • Enable Flask’s SESSION_COOKIE_SECURE and CS
  • Python Github Oauth Authentication Flow

    When you want to let users log in to your Python web application using their GitHub accounts, the GitHub OAuth authentication flow is the industry‑standard solution. It enables you to securely obtain an access token, fetch user data, and personalize the experience without ever handling passwords directly. In this guide we’ll walk through every step of the Python GitHub OAuth authentication flow, from registering your app on GitHub to writing clean, production‑ready code with Flask (or any WSGI framework). By the end you’ll have a solid, SEO‑friendly reference that you can copy‑paste into your own projects.

    Why Choose GitHub OAuth for Python Projects?

    • Secure delegation: Users authenticate on GitHub, not on your server.
    • Rich developer data: Access public profile, email, repositories, and more.
    • Standardized protocol: OAuth 2.0 is widely supported and well‑documented.
    • Python ecosystem: Libraries like requests, authlib, and Flask‑Login simplify implementation.

    Prerequisites Before You Start

    • Python 3.8+ installed on your development machine.
    • A GitHub account (obviously) and permission to create OAuth apps.
    • Basic familiarity with a Python web framework (Flask, Django, FastAPI, etc.).
    • Installed dependencies:
      pip install Flask requests authlib

    Step 1: Register Your OAuth Application on GitHub

    Creating the app

    1. Navigate to GitHub Settings → Developer settings → OAuth Apps.
    2. Click New OAuth App.
    3. Fill in the required fields:
      • Application name: e.g., MyPythonApp
      • Homepage URL: https://myapp.example.com/
      • Authorization callback URL: https://myapp.example.com/auth/callback
    4. Save the app. GitHub will generate a Client ID and a Client Secret**. Store them securely (environment variables are recommended).

    Step 2: Understanding the OAuth 2.0 Flow

    GitHub follows the standard Authorization Code Grant flow. The sequence is:

    1. Authorization request: Your app redirects the user to GitHub’s consent page.
    2. User grants permission: GitHub asks the user to approve the requested scopes.
    3. Redirect with code: GitHub redirects back to your callback URL with a temporary code parameter.
    4. Token exchange: Your server sends the code, client ID, and client secret to GitHub’s token endpoint.
    5. Access token received: GitHub returns a JSON payload containing the access_token.
    6. API calls: Use the token in the Authorization: token <access_token> header to fetch user data.

    Step 3: Implementing the Flow in Python

    Project structure

    .
    ├─ app.py               # Main Flask application
    ├─ config.py            # Environment variables & settings
    └─ requirements.txt    # Dependencies

    Configuration (config.py)

    import os
    
    class Config:
        GITHUB_CLIENT_ID = os.getenv('GITHUB_CLIENT_ID')
        GITHUB_CLIENT_SECRET = os.getenv('GITHUB_CLIENT_SECRET')
        SECRET_KEY = os.getenv('FLASK_SECRET_KEY', 'dev-secret')
        # The URL where GitHub will redirect after auth
        GITHUB_REDIRECT_URI = os.getenv('GITHUB_REDIRECT_URI',
                                        'http://localhost:5000/auth/callback')
        # Scopes you need – adjust as required
        GITHUB_OAUTH_SCOPE = 'read:user user:email'

    Flask application (app.py)

    from flask import Flask, redirect, url_for, request, session, jsonify
    import requests
    from authlib.integrations.flask_client import OAuth
    from config import Config
    
    app = Flask(__name__)
    app.config.from_object(Config)
    
    # Initialize OAuth registry
    oauth = OAuth(app)
    github = oauth.register(
        name='github',
        client_id=app.config['GITHUB_CLIENT_ID'],
        client_secret=app.config['GITHUB_CLIENT_SECRET'],
        access_token_url='https://github.com/login/oauth/access_token',
        authorize_url='https://github.com/login/oauth/authorize',
        api_base_url='https://api.github.com/',
        client_kwargs={'scope': app.config['GITHUB_OAUTH_SCOPE']},
    )
    
    @app.route('/')
    def index():
        user = session.get('github_user')
        if user:
            return f\"

    Welcome, {user['login']}!

    Logout

    \" return \"

    Python GitHub OAuth Demo

    Login with GitHub\" @app.route('/login') def login(): # Step 1 – redirect user to GitHub's consent page redirect_uri = url_for('auth_callback', _external=True) return github.authorize_redirect(redirect_uri) @app.route('/auth/callback') def auth_callback(): # Step 4 – exchange the temporary code for an access token token = github.authorize_access_token() # Store token securely (session is fine for demo) session['github_token'] = token # Step 5 – fetch user profile resp = github.get('user') profile = resp.json() session['github_user'] = profile # Optional: fetch primary email if not public if not profile.get('email'): emails_resp = github.get('user/emails') emails = emails_resp.json() primary = next((e['email'] for e in emails if e['primary']), None) session['github_user']['email'] = primary return redirect(url_for('index')) @app.route('/logout') def logout(): session.clear() return redirect(url_for('index')) if __name__ == '__main__': app.run(debug=True)

    Key points in the code

    • Redirect URI is built dynamically with url_for(..., _external=True) so it works locally and in production.
    • github.authorize_redirect() automatically adds client_id, redirect_uri, and scope to the URL.
    • github.authorize_access_token() handles the POST request to GitHub’s token endpoint and parses the JSON response.
    • All API calls use the same github client, which injects the Authorization header for you.

    Step 4: Security Best Practices

    • Never hard‑code client secrets. Use environment variables or a secret manager (AWS Secrets Manager, HashiCorp Vault, etc.).
    • Use HTTPS for both your site and the callback URL. GitHub rejects insecure redirect URIs for production apps.
    • Validate the state parameter if you implement it manually. authlib does this automatically, but custom implementations should generate a random nonce, store it in the session, and compare it on callback.
    • Limit scopes to the minimum required. Requesting repo when you only need read:user raises unnecessary risk.
    • Rotate client secrets periodically and revoke tokens when users log out or when suspicious activity is detected.

    Common Pitfalls & How to Debug Them

    1. Redirect URI mismatch – GitHub will return a redirect_uri mismatch error if the URL you send does not exactly match the one registered. Double‑check trailing slashes and protocol (http vs https).
    2. Missing state validation – If you turn off authlib’s built‑in state handling, CSRF attacks become possible. Always verify the state you sent.
    3. Rate limiting – Unauthenticated GitHub API calls are limited to 60 requests/hour. Use the access token for higher limits (5,000 requests/hour per user).
    4. Expired authorization code – The temporary code is valid for only a few minutes. Ensure you exchange it immediately in the callback route.
    5. Incorrect token parsing – GitHub returns the token as application/x-www-form-urlencoded by default. Libraries like requests handle it, but if you parse manually, use response.json() or urllib.parse.parse_qs.

    Testing the Flow Locally

    During development you can use http://localhost:5000/auth/callback as the redirect URI. GitHub allows localhost URLs, but remember to switch to a fully qualified domain with HTTPS before going live. Tools like ngrok can expose your local server to the internet for quick integration tests.

    Deploying to Production

    • Set FLASK_ENV=production and configure a WSGI server (Gunicorn, uWSGI).
  • Python Google Oauth2 Login Integration

    Integrating Google OAuth2 login into a Python web application is one of the most effective ways to provide a seamless, secure, and frictionless authentication experience for users. By leveraging Google’s trusted identity platform, developers can offload password management, reduce signup friction, and boost conversion rates—all while keeping their codebase clean and maintainable. In this guide, we’ll walk through the entire process: from setting up a Google Cloud project to implementing OAuth2 in both Flask and Django, handling tokens securely, and troubleshooting common pitfalls. Whether you’re building a small prototype or a production‑grade SaaS, the steps below will give you a solid foundation for Python Google OAuth2 login integration.

    Why Choose Google OAuth2 for Your Python App?

    • Trusted security: Google’s infrastructure follows industry‑leading security standards, including multi‑factor authentication and anomaly detection.
    • Reduced password fatigue: Users can sign in with an existing Google account, eliminating the need to remember another password.
    • Rich user profile data: With a single consent screen, you can retrieve email, name, profile picture, and even locale information.
    • Scalable and future‑proof: OAuth2 is the de‑facto standard for modern authentication, making it easy to add other providers later (e.g., Facebook, GitHub).

    Prerequisites

    1. Basic knowledge of Python and a web framework (Flask or Django).
    2. Python 3.8+ installed on your development machine.
    3. A Google account to access the Google Cloud Console.
    4. Virtual environment tool (venv, pipenv, or poetry) for dependency isolation.

    Step 1: Create a Google Cloud Project and OAuth2 Credentials

    1.1 Enable the Google Identity Services API

    Log in to the Google Cloud Console, create a new project (or select an existing one), and navigate to APIs & Services > Library. Search for Google Identity Services API and click Enable.

    1.2 Configure OAuth Consent Screen

    Under APIs & Services > OAuth consent screen, choose External for public apps. Fill in the required fields:

    • App name, support email, and developer contact information.
    • Scopes you need (e.g., email, profile, openid).
    • Authorized domains (e.g., localhost for development, your production domain for live).

    Save the consent screen; Google will review it if you request sensitive scopes.

    1.3 Generate Client ID and Client Secret

    Go to Credentials > Create Credentials > OAuth client ID. Choose Web application and set the following:

    • Authorized JavaScript origins: http://localhost:5000 (Flask) or http://127.0.0.1:8000 (Django).
    • Authorized redirect URIs: http://localhost:5000/auth/callback (Flask) or http://127.0.0.1:8000/oauth2callback/ (Django).

    After creation, note the Client ID and Client Secret. Store them securely (e.g., in .env).

    Step 2: Install Required Python Packages

    Both Flask and Django have mature extensions for OAuth2. The most popular choices are Authlib and python-social-auth. Below we’ll use Authlib for its simplicity and modern API.

    pip install Flask Authlib        # For Flask projects
    pip install Django Authlib       # For Django projects
    pip install python-dotenv        # Optional: load .env files
    

    Step 3: Implement Google OAuth2 in Flask

    3.1 Project Structure

    .
    ├─ app.py
    ├─ templates/
    │  ├─ login.html
    │  └─ profile.html
    └─ .env
    

    3.2 .env File (Never commit secrets)

    GOOGLE_CLIENT_ID=YOUR_CLIENT_ID.apps.googleusercontent.com
    GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET
    SECRET_KEY=your_flask_secret_key
    

    3.3 Flask Application Code

    from flask import Flask, redirect, url_for, session, render_template, request
    from authlib.integrations.flask_client import OAuth
    from dotenv import load_dotenv
    import os
    
    load_dotenv()  # Load .env variables
    
    app = Flask(__name__)
    app.secret_key = os.getenv('SECRET_KEY')
    
    # Configure OAuth
    oauth = OAuth(app)
    google = oauth.register(
        name='google',
        client_id=os.getenv('GOOGLE_CLIENT_ID'),
        client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
        access_token_url='https://oauth2.googleapis.com/token',
        authorize_url='https://accounts.google.com/o/oauth2/v2/auth',
        client_kwargs={'scope': 'openid email profile'},
    )
    
    @app.route('/')
    def index():
        user = session.get('user')
        return render_template('login.html', user=user)
    
    @app.route('/login')
    def login():
        redirect_uri = url_for('auth_callback', _external=True)
        return google.authorize_redirect(redirect_uri)
    
    @app.route('/auth/callback')
    def auth_callback():
        token = google.authorize_access_token()
        resp = google.get('userinfo')
        user_info = resp.json()
        # Store user info in session (or DB for production)
        session['user'] = {
            'id': user_info['sub'],
            'name': user_info['name'],
            'email': user_info['email'],
            'picture': user_info['picture'],
        }
        return redirect(url_for('profile'))
    
    @app.route('/profile')
    def profile():
        user = session.get('user')
        if not user:
            return redirect(url_for('index'))
        return render_template('profile.html', user=user)
    
    @app.route('/logout')
    def logout():
        session.clear()
        return redirect(url_for('index'))
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    3.4 Template Snippets

    login.html

    <!DOCTYPE html>
    <html>
    <body>
        {% if user %}
            <p>Welcome, <strong>{{ user.name }}</strong>!</p>
            <a href="{{ url_for('profile') }}">View Profile</a>
            <a href="{{ url_for('logout') }}">Logout</a>
        {% else %}
            <a href="{{ url_for('login') }}">Sign in with Google</a>
        {% endif %}
    </body>
    </html>
    

    profile.html

    <!DOCTYPE html>
    <html>
    <body>
        <h2>User Profile</h2>
        <img src="{{ user.picture }}" alt="Profile picture" width="100">
        <p><strong>Name: {{ user.name }}</p>
        <p><strong>Email: {{ user.email }}</p>
        <a href="{{ url_for('logout') }}">Logout</a>
    </body>
    </html>
    

    Step 4: Implement Google OAuth2 in Django

    4.1 Project Setup

    django-admin startproject mysite
    cd mysite
    python manage.py startapp accounts
    pip install django-authlib python-dotenv
    

    4.2 Settings Adjustments (mysite/settings.py)

    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
    DEBUG = True
    ALLOWED_HOSTS = []
    
    INSTALLED_APPS = [
        # default apps …
        'django.contrib.sessions',
        'accounts',
    ]
    
    MIDDLEWARE = [
        # default middleware …
        'django.contrib.sessions.middleware.SessionMiddleware',
    ]
    
    # OAuth2 configuration
    GOOGLE_CLIENT_ID = os.getenv('GOOGLE_CLIENT_ID')
    GOOGLE_CLIENT_SECRET = os.getenv('GOOGLE_CLIENT_SECRET')
    

    4.3 URL Configuration (mysite/urls.py)

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', include('accounts.urls')),
    ]
    

    4.4 Accounts App URLs (accounts/urls.py)

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.home, name='home'),
        path('login/', views.login, name='login'),
        path('oauth2callback/', views.auth_callback, name='auth_callback'),
        path('profile/', views.profile, name='profile'),
        path('logout/', views.logout_view, name='logout'),
    ]
    

    4.5 Views Implementation (accounts/views.py)

    from django.shortcuts import render, redirect
    from django.conf import settings
    from authlib.integrations.django_client import OAuth
    from django.http import HttpResponse

    oauth = OAuth()
    google = oauth.register(
    name='google',
    client_id=settings.GOOGLE_CLIENT_ID,
    client_secret=settings.GOOGLE_CLIENT

  • Python Web App Rate Limiting With Redis

    When you launch a Python web application, protecting it from abuse, accidental overload, or malicious attacks is crucial. Rate limiting—the practice of restricting the number of requests a client can make in a given time window—helps keep your service responsive, preserves backend resources, and improves overall user experience. Among the many tools available, Redis stands out as a fast, in‑memory data store that can enforce rate limits with sub‑millisecond latency. In this guide we’ll explore why rate limiting matters, how Redis powers efficient limits, and walk through a complete, production‑ready implementation for Python web apps.

    Why Rate Limiting Matters for Python Web Apps

    Even the most robust Python frameworks (Flask, Django, FastAPI, etc.) cannot protect themselves from traffic spikes or abusive clients on their own. Without proper throttling you may encounter:

    • Server overload: Excessive requests consume CPU, memory, and database connections, leading to timeouts.
    • Denial‑of‑service (DoS) attacks: Attackers can flood endpoints, rendering the service unavailable for legitimate users.
    • API abuse: Public APIs often need per‑user or per‑IP quotas to prevent data scraping or unfair usage.
    • Cost escalation: Cloud providers charge for outbound bandwidth and compute; uncontrolled traffic can blow up your bill.

    Common Scenarios That Need Rate Limiting

    1. Login endpoints – limit attempts per IP to mitigate brute‑force attacks.
    2. Public APIs – enforce a “requests per minute” quota per API key.
    3. File upload services – cap the size and frequency of uploads per user.
    4. Search pages – prevent query spamming that could degrade search performance.

    How Redis Enables Efficient Rate Limiting

    Redis is a key‑value store that lives entirely in RAM, offering O(1) read/write operations and built‑in data structures ideal for counting and time‑window calculations. Its features that make it perfect for rate limiting include:

    • Atomic commands: Operations like INCR, EXPIRE, and SETNX are atomic, preventing race conditions in high‑concurrency environments.
    • TTL (Time‑to‑Live): Keys can automatically expire after a defined period, simplifying sliding‑window implementations.
    • Lua scripting: Execute multiple commands in a single round‑trip, ensuring consistency for complex algorithms.
    • Scalability: Redis can be clustered across multiple nodes, handling millions of operations per second.

    Redis Data Structures for Rate Limiting

    Depending on the algorithm you choose, you might use:

    • String counters: Simple INCR with an expiration for fixed‑window limits.
    • Sorted sets (ZSET): Store timestamps of each request; useful for sliding‑window or leaky‑bucket approaches.
    • Hashes: Group multiple counters (e.g., per‑user, per‑endpoint) under a single key to reduce key space.

    Implementing the Token Bucket Algorithm with Redis in Python

    The token bucket algorithm is a flexible, burst‑friendly method that allows short spikes while maintaining an average request rate. Below is a step‑by‑step implementation using the redis-py client and a Lua script to keep the operation atomic.

    Step‑by‑Step Explanation

    1. Define bucket parameters: capacity (max tokens) and refill rate (tokens per second).
    2. Store the bucket state: Two fields in a Redis hash – tokens (current token count) and timestamp (last refill time).
    3. Lua script logic:
      • Calculate elapsed time since the last refill.
      • Add tokens based on the elapsed time and refill rate, capping at the bucket capacity.
      • If enough tokens exist, decrement the count and allow the request.
      • Otherwise, reject the request.
    4. Call the script from Python: Pass the user identifier (IP, API key, etc.) as the Redis key.
    import time
    import redis
    
    # Initialize Redis connection (adjust host/port as needed)
    redis_client = redis.StrictRedis(host='localhost', port=6379, db=0)
    
    # Lua script that implements token bucket atomically
    TOKEN_BUCKET_LUA = """
    local key = KEYS[1]
    local capacity = tonumber(ARGV[1])
    local refill_rate = tonumber(ARGV[2])
    local now = tonumber(ARGV[3])
    
    -- Retrieve current token count and timestamp
    local bucket = redis.call('HMGET', key, 'tokens', 'timestamp')
    local tokens = tonumber(bucket[1]) or capacity
    local timestamp = tonumber(bucket[2]) or now
    
    -- Refill tokens based on elapsed time
    local elapsed = now - timestamp
    local refill = elapsed * refill_rate
    tokens = math.min(tokens + refill, capacity)
    
    if tokens < 1 then
        -- Not enough tokens – reject request
        redis.call('HMSET', key, 'tokens', tokens, 'timestamp', now)
        redis.call('EXPIRE', key, math.ceil(capacity / refill_rate))
        return 0
    else
        -- Consume a token – allow request
        tokens = tokens - 1
        redis.call('HMSET', key, 'tokens', tokens, 'timestamp', now)
        redis.call('EXPIRE', key, math.ceil(capacity / refill_rate))
        return 1
    end
    """
    
    # Load script into Redis and get SHA for future calls
    script_sha = redis_client.script_load(TOKEN_BUCKET_LUA)
    
    def is_allowed(user_id: str, capacity: int = 10, refill_rate: float = 1.0) -> bool:
        """
        Returns True if the request should be processed, False otherwise.
        - capacity: maximum number of tokens in the bucket.
        - refill_rate: tokens added per second.
        """
        now = time.time()
        result = redis_client.evalsha(
            script_sha,
            1,                     # Number of keys
            f"rate_limit:{user_id}",
            capacity,
            refill_rate,
            now
        )
        return bool(result)
    
    # Example usage in a Flask route
    from flask import Flask, request, jsonify
    
    app = Flask(__name__)
    
    @app.route('/api/data')
    def get_data():
        client_ip = request.remote_addr
        if not is_allowed(client_ip, capacity=20, refill_rate=5):
            return jsonify({'error': 'Rate limit exceeded'}), 429
        return jsonify({'message': 'Here is your data!'})
    

    This snippet demonstrates a production‑ready pattern: the heavy lifting happens inside Redis, guaranteeing that even under thousands of concurrent requests the token count stays consistent.

    Using Flask‑Limiter and Redis for Quick Setup

    If you prefer a higher‑level solution, the Flask‑Limiter extension abstracts most of the boilerplate while still using Redis as its storage backend.

    Installation and Setup

    pip install Flask-Limiter redis

    Configure the limiter in your Flask app:

    from flask import Flask, jsonify
    from flask_limiter import Limiter
    from flask_limiter.util import get_remote_address
    import redis
    
    app = Flask(__name__)
    
    # Create a Redis connection that Flask‑Limiter will use
    redis_store = redis.StrictRedis(host='localhost', port=6379, db=0)
    
    limiter = Limiter(
        key_func=get_remote_address,
        storage_uri="redis://localhost:6379/0"
    )
    
    # Apply a global limit: 100 requests per minute per IP
    limiter.limit("100 per minute")(app)
    
    @app.route('/public')
    def public_endpoint():
        return jsonify({'msg': 'This endpoint is rate‑limited!'})
    
    # Per‑route limit example: 5 requests per 10 seconds
    @app.route('/login')
    @limiter.limit("5 per 10 seconds")
    def login():
        return jsonify({'msg': 'Login attempt'})
    
    if __name__ == '__main__':
        app.run(debug=True)

    Flask‑Limiter automatically handles key generation, expiration, and response headers (Retry-After, X-RateLimit-Limit, etc.), saving you time while still giving you full control over the Redis backend.

    Best Practices and Tips for Production Environments

    • Choose the right algorithm: Fixed‑window is simple but can cause bursty traffic spikes; sliding‑window or token bucket smooths traffic.
    • Store per‑user keys efficiently: Prefix keys (e.g., rl:ip:123.45.67.89) and consider using hashes to keep the key count low.
    • Set appropriate TTLs: Expire keys shortly after they become irrelevant to avoid memory bloat.
    • Monitor Redis memory: Use INFO memory and set maxmemory-policy to allkeys-lru for automatic eviction.
    • Graceful degradation: If Redis is unavailable, decide whether to allow all traffic (fail‑open) or reject everything (fail‑closed) based on your risk tolerance.
    • Rate‑limit headers: Return X-RateLimit-Remaining and Retry-After
  • Python Cors Configuration Guide

    Cross‑Origin Resource Sharing (CORS) is a cornerstone of modern web development, allowing browsers to safely request resources from a different domain than the one that served the page. If you’re building APIs or web services with Python, mastering CORS configuration is essential to keep your applications secure while delivering a seamless user experience. In this guide we’ll walk through the fundamentals of CORS, show you how to configure it in the three most popular Python frameworks—Flask, Django, and FastAPI—and share practical tips for testing and troubleshooting.

    What Is CORS and How Does It Work?

    CORS is a browser‑level security feature that controls which origins (domains, protocols, or ports) are permitted to read resources from a server. When a web page makes a cross‑origin request, the browser sends a Origin header. The server then decides whether to include an Access-Control-Allow-Origin header in its response. If the header matches the requesting origin (or is a wildcard *), the browser allows the response to be accessed by JavaScript; otherwise, it blocks the data.

    Key CORS response headers

    • Access-Control-Allow-Origin: Specifies the allowed origin(s). Example: Access-Control-Allow-Origin: https://example.com
    • Access-Control-Allow-Methods: Lists HTTP methods permitted for the request (GET, POST, PUT, DELETE, etc.).
    • Access-Control-Allow-Headers: Indicates which custom headers the client may send.
    • Access-Control-Allow-Credentials: When set to true, cookies and HTTP authentication are allowed.
    • Access-Control-Max-Age: Caches the pre‑flight response for a specified number of seconds.

    Why Configure CORS in Python Applications?

    Without proper CORS handling, your API may either:

    • Reject legitimate requests from trusted front‑ends, breaking functionality.
    • Expose sensitive data to malicious sites if you use a permissive wildcard configuration.

    Python frameworks provide middleware or extensions that automate header management, letting you focus on business logic while maintaining security best practices.

    Configuring CORS in Flask

    Flask is lightweight, and the most common way to handle CORS is with the flask‑cors extension.

    Step‑by‑step setup

    1. Install the extension:
      pip install flask-cors
    2. Import and initialize it in your application:
      from flask import Flask
      from flask_cors import CORS
      
      app = Flask(__name__)
      
      # Allow all origins (use with caution)
      CORS(app)
      
      # OR configure specific origins
      CORS(app, resources={
          r"/api/*": {"origins": ["https://frontend.example.com", "https://admin.example.com"]},
          r"/public/*": {"origins": "*"}
      })
    3. Fine‑tune individual routes if needed:
      @app.route("/api/data")
      @cross_origin(origins="https://frontend.example.com", methods=["GET", "POST"])
      def get_data():
          return {"message": "CORS enabled for this endpoint"}

    Best practices for Flask

    • Never use * for Access-Control-Allow-Origin when Access-Control-Allow-Credentials is true.
    • Restrict methods and headers to the minimum required.
    • Separate public and private API namespaces and apply different CORS rules.

    Configuring CORS in Django

    Django’s built‑in middleware system makes CORS handling straightforward with the django-cors-headers package.

    Installation and basic configuration

    1. Add the package:
      pip install django-cors-headers
    2. Update settings.py:
      INSTALLED_APPS = [
          ...,
          "corsheaders",
      ]
      
      MIDDLEWARE = [
          "corsheaders.middleware.CorsMiddleware",
          "django.middleware.common.CommonMiddleware",
          ...,
      ]
      
      # Allow only specific origins
      CORS_ALLOWED_ORIGINS = [
          "https://frontend.example.com",
          "https://admin.example.com",
      ]
      
      # Optional: allow all subdomains of a domain
      CORS_ALLOWED_ORIGIN_REGEXES = [
          r"^https://\w+\.example\.com$",
      ]
      
      # Enable credentials if needed
      CORS_ALLOW_CREDENTIALS = True
      
      # Restrict methods
      CORS_ALLOW_METHODS = [
          "GET",
          "POST",
          "PUT",
          "PATCH",
          "DELETE",
      ]
    3. For per‑view control, use the decorator:
      from corsheaders.decorators import cors_allow_all, cors_allow_origin
      
      @cors_allow_origin("https://frontend.example.com")
      def my_view(request):
          ...

    Tips for Django projects

    • Place CorsMiddleware as high as possible in the middleware list to ensure headers are added before other processing.
    • Combine CORS_ALLOW_ALL_ORIGINS = False with an explicit whitelist for tighter security.
    • Leverage CORS_EXPOSE_HEADERS when you need the client to read custom response headers.

    Configuring CORS in FastAPI

    FastAPI, built on Starlette, uses a simple CORSMiddleware that can be added directly to the application instance.

    Implementation steps

    1. Install FastAPI and Uvicorn (if not already):
      pip install fastapi uvicorn
    2. Add the middleware:
      from fastapi import FastAPI
      from fastapi.middleware.cors import CORSMiddleware
      
      app = FastAPI()
      
      origins = [
          "https://frontend.example.com",
          "https://admin.example.com",
      ]
      
      app.add_middleware(
          CORSMiddleware,
          allow_origins=origins,
          allow_credentials=True,
          allow_methods=["GET", "POST", "PUT", "DELETE"],
          allow_headers=["*"],  # Adjust as needed
          max_age=600,
      )
    3. Define your routes normally; the middleware will handle CORS for all paths unless you create a separate APIRouter with its own settings.

    FastAPI CORS checklist

    • Use a list of origins instead of * when allow_credentials=True.
    • Set max_age to reduce pre‑flight traffic for high‑traffic endpoints.
    • When serving static files, remember that the same middleware applies unless you mount a separate StaticFiles instance with its own configuration.

    Common Pitfalls and How to Avoid Them

    Even seasoned developers can stumble over subtle CORS issues. Below are the most frequent mistakes and quick fixes.

    1. Using a wildcard with credentials

    Browsers reject responses that contain Access-Control-Allow-Credentials: true together with Access-Control-Allow-Origin: *. Always specify explicit origins when credentials are required.

    2. Forgetting to handle pre‑flight OPTIONS requests

    Some frameworks automatically respond to OPTIONS requests, but if you have custom routing logic you may need to add an explicit handler:

    @app.route("/api/resource", methods=["OPTIONS"])
    def options_handler():
        response = make_response()
        response.headers["Access-Control-Allow-Origin"] = "https://frontend.example.com"
        response.headers["Access-Control-Allow-Methods"] = "GET,POST,PUT,DELETE"
        response.headers["Access-Control-Allow-Headers"] = "Content-Type,Authorization"
        return response

    3. Over‑exposing headers

    Only expose the headers your client actually needs. Unnecessary exposure can leak internal implementation details.

    4. Ignoring sub‑domain variations

    If your front‑end uses dynamic sub‑domains (e.g., user1.example.com), use regex‑based origin matching instead of enumerating each sub‑domain.

    Testing Your CORS Configuration

    Automated testing ensures that CORS behaves as expected across environments.

    Manual testing with browser dev tools

    • Open the Network tab, make a cross‑origin request, and inspect the response headers.
    • Look for Access-Control-Allow-Origin and verify it matches the request’s Origin.
  • Python Csrf Protection In Web Applications

    Cross‑Site Request Forgery (CSRF) remains one of the most sneaky web vulnerabilities, and Python developers often wonder how to defend their applications without sacrificing performance or developer ergonomics. In this guide we’ll explore what CSRF is, why it matters, and how to implement rock‑solid protection in the most popular Python web frameworks—Django, Flask, and FastAPI. You’ll also learn the underlying principles, see code‑level examples, and walk away with a ready‑to‑use checklist that keeps your site safe and your SEO rankings high.

    Understanding CSRF and Its Risks

    What is CSRF?

    CSRF exploits the trust that a web browser has in a logged‑in user. An attacker tricks the victim’s browser into sending a state‑changing request (such as POST /transfer) to a target site where the user is already authenticated. Because the browser automatically includes cookies, the request appears legitimate, and the server processes it as if the user had initiated the action.

    Real‑world impact

    • Financial loss: Unauthorized fund transfers, subscription cancellations, or purchase orders.
    • Data integrity: Deleting or modifying user records, changing passwords, or altering settings.
    • Reputation damage: Users lose trust when their accounts are compromised, which can hurt search rankings and organic traffic.

    Core Principles of CSRF Protection

    • Synchronizer token pattern: Generate a unique, unpredictable token per user session and require it on every state‑changing request.
    • SameSite cookie attribute: Instruct browsers not to send cookies on cross‑origin requests (e.g., SameSite=Lax or Strict).
    • Double‑submit cookie: Send the token both as a cookie and as a request parameter, then compare them on the server.
    • Origin/Referer validation: Verify that the Origin or Referer header matches your domain for non‑GET requests.

    When these principles are combined, an attacker’s forged request will lack a valid token or will be blocked by the browser, effectively neutralizing the threat.

    Implementing CSRF Protection in Popular Python Frameworks

    Django – Built‑in CSRF Middleware

    Django ships with a mature CSRF system that works out of the box. The CsrfViewMiddleware validates tokens for any POST, PUT, PATCH, or DELETE request.

    # settings.py
    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',  # ← enabled by default
        # …
    ]
    
    # template.html
    <form method="post" action="/submit/">
        {% csrf_token %}
        <input type="text" name="name">
        <button type="submit">Send</button>
    </form>
    

    The {% csrf_token %} tag injects a hidden input containing the session‑specific token. Django also sets a csrftoken cookie, enabling the double‑submit pattern for AJAX calls:

    fetch('/api/data/', {
        method: 'POST',
        headers: {
            'X-CSRFToken': getCookie('csrftoken'),  // custom helper
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({key: 'value'})
    });
    

    Flask – Using Flask‑WTF or Manual Tokens

    Flask does not include CSRF protection by default, but the Flask‑WTF extension adds a seamless layer.

    # app.py
    from flask import Flask, render_template, request
    from flask_wtf import CSRFProtect
    
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'a-very-secret-key'
    csrf = CSRFProtect(app)   # ← activates protection for all POST routes
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            # process login
            pass
        return render_template('login.html')
    

    In your Jinja2 template, include the token with {{ csrf_token() }}:

    <form method="post" action="{{ url_for('login') }}">
        <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
        <input type="text" name="username">
        <input type="password" name="password">
        <button type="submit">Log In</button>
    </form>
    

    If you prefer a lightweight approach, you can generate and verify tokens manually:

    import secrets
    from flask import session, abort, request
    
    def generate_csrf_token():
        token = secrets.token_urlsafe(32)
        session['csrf_token'] = token
        return token
    
    def validate_csrf():
        token = session.get('csrf_token')
        header = request.headers.get('X-CSRFToken') or request.form.get('csrf_token')
        if not token or token != header:
            abort(400, 'Invalid CSRF token')
    

    FastAPI – Middleware for Token Validation

    FastAPI, built on Starlette, encourages explicit security layers. Below is a minimal CSRF middleware that checks a token stored in a signed cookie.

    # csrf_middleware.py
    from starlette.middleware.base import BaseHTTPMiddleware
    from starlette.requests import Request
    from starlette.responses import Response
    from itsdangerous import URLSafeSerializer, BadSignature
    import os
    
    serializer = URLSafeSerializer(os.getenv('SECRET_KEY', 'fallback-secret'))
    
    class CSRFMiddleware(BaseHTTPMiddleware):
        async def dispatch(self, request: Request, call_next):
            # Only protect unsafe methods
            if request.method not in ('GET', 'HEAD', 'OPTIONS'):
                cookie = request.cookies.get('csrf_token')
                header = request.headers.get('X-CSRF-Token')
                if not cookie or not header:
                    return Response('CSRF token missing', status_code=400)
                try:
                    token = serializer.loads(cookie)
                    if token != header:
                        raise ValueError('Token mismatch')
                except (BadSignature, ValueError):
                    return Response('Invalid CSRF token', status_code=400)
            response = await call_next(request)
            # Set token for safe methods
            if request.method == 'GET' and 'csrf_token' not in request.cookies:
                token = serializer.dumps(secrets.token_urlsafe(32))
                response.set_cookie('csrf_token', token, httponly=False, samesite='Lax')
            return response
    
    # main.py
    from fastapi import FastAPI, Request
    from csrf_middleware import CSRFMiddleware
    
    app = FastAPI()
    app.add_middleware(CSRFMiddleware)
    
    @app.post('/comment')
    async def add_comment(request: Request):
        data = await request.json()
        # process comment
        return {'status': 'saved'}
    

    Clients send the token via the X-CSRF-Token header, which the middleware validates against the signed cookie.

    Manual CSRF Token Management (When Framework Support Is Not Enough)

    Sometimes you need a custom solution—perhaps for a microservice that only serves JSON APIs. Follow these steps:

    1. Generate a cryptographically strong token. Use secrets.token_urlsafe() and store it in the user’s session or a signed cookie.
    2. Expose the token to the client. Render it in HTML, return it in a JSON payload, or set it as a cookie with SameSite=Lax.
    3. Require the token on every state‑changing request. Accept it via a custom header (e.g., X-CSRF-Token) or a hidden form field.
    4. Validate the token server‑side. Compare the received value with the stored one; reject the request with 400 Bad Request on mismatch.
    5. Rotate the token periodically. Regenerate after login, logout, or every few hours to limit exposure.

    Common Pitfalls and How to Avoid Them

    • Disabling CSRF for JSON endpoints. Never blanket‑disable protection; instead, enforce token checks on application/json requests just like form posts.
    • Storing tokens in insecure cookies. Mark CSRF cookies as HttpOnly=False (so JavaScript can read them) but always set Secure and SameSite=Lax in production.
    • Relying solely on