Category: Uncategorized

  • Python Https Local Development Setup

    Setting up a secure HTTPS environment while developing Python web applications locally can feel like a daunting task, but it’s essential for testing OAuth callbacks, service‑worker behavior, and any feature that depends on a trusted TLS connection. In this guide we’ll walk through everything you need to spin up a fully functional HTTPS server on your workstation, from generating self‑signed certificates with openssl to configuring popular frameworks such as Flask, Django, and FastAPI. By the end, you’ll have a repeatable workflow that keeps your development cycle fast, safe, and SEO‑friendly.

    Why Develop Over HTTPS?

    Modern browsers enforce strict security policies: mixed content (HTTP pages loading HTTPS resources) is blocked, Service Workers require a secure context, and many third‑party APIs (Google, Stripe, etc.) reject non‑TLS callbacks. Testing these integrations on plain HTTP can hide bugs that only surface in production. Moreover, search engines reward sites that consistently serve content over HTTPS, so early adoption helps you avoid SEO pitfalls later on.

    Prerequisites

    • Python 3.8+ installed on your machine.
    • A terminal with openssl (comes with macOS/Linux; Windows users can install Git Bash or use WSL).
    • One of the following frameworks installed via pip:
      • Flask (pip install flask)
      • Django (pip install django)
      • FastAPI with Uvicorn (pip install fastapi uvicorn)

    Step 1: Generate a Self‑Signed Certificate

    A self‑signed certificate is sufficient for local development because you control the trust store on your own machine. Follow these commands to create a private key and a certificate that’s valid for 365 days.

    # Create a private key
    openssl genrsa -out localdev.key 2048
    
    # Generate a certificate signing request (CSR)
    openssl req -new -key localdev.key -out localdev.csr \
        -subj "/C=US/ST=California/L=SanFrancisco/O=MyLocalDev/OU=Dev/CN=localhost"
    
    # Sign the certificate (self‑signed)
    openssl x509 -req -days 365 -in localdev.csr -signkey localdev.key -out localdev.crt
    

    Place localdev.key and localdev.crt in a secure folder within your project (e.g., certs/) and add that folder to .gitignore to avoid committing private keys.

    Step 2: Trust the Certificate on Your Local Machine

    Browsers will still flag the certificate as “not trusted” unless you add it to your OS’s trust store. Here’s how to do it on the three major platforms:

    macOS

    • Open Keychain Access.
    • Drag localdev.crt into the “System” keychain.
    • Double‑click the certificate, expand “Trust”, and set “When using this certificate” to Always Trust.

    Windows

    • Run mmc → File → Add/Remove Snap‑in → Certificates → “Computer account”.
    • Navigate to Trusted Root Certification Authorities → Certificates and import localdev.crt.

    Linux (Ubuntu/Debian)

    sudo cp localdev.crt /usr/local/share/ca-certificates/localdev.crt
    sudo update-ca-certificates
    

    Step 3: Configure Your Python Framework

    Each framework has a slightly different way to enable HTTPS. Below are minimal examples that you can copy‑paste into your project.

    Flask

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def hello():
        return "Hello, secure Flask!"
    
    if __name__ == "__main__":
        # Provide the path to the certificate and key
        app.run(host="127.0.0.1", port=8443, ssl_context=("certs/localdev.crt", "certs/localdev.key"))
    

    Run the app with python app.py and visit https://localhost:8443. Your browser should show a secure lock icon if the certificate is trusted.

    Django

    Django’s built‑in development server can serve HTTPS when you pass the --cert and --key options (available from Django 4.2 onward). First, create a manage.py command or use the built‑in one:

    # From the project root
    python manage.py runserver_plus 0.0.0.0:8443 \
        --cert-file certs/localdev.crt \
        --key-file certs/localdev.key
    

    If you’re on an older Django version, you can wrap the WSGI app with ssl.wrap_socket manually:

    import ssl
    from django.core.management import execute_from_command_line
    
    if __name__ == "__main__":
        execute_from_command_line()
        # After the server starts, you can use a reverse proxy like nginx
    

    For most developers, upgrading to the latest Django release is the simplest path.

    FastAPI with Uvicorn

    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    def read_root():
        return {"message": "Secure FastAPI"}
    
    # Save this as main.py and run:
    # uvicorn main:app --host 127.0.0.1 --port 8443 --ssl-keyfile certs/localdev.key --ssl-certfile certs/localdev.crt
    

    Step 4: Automate the Workflow with a Makefile or Scripts

    Repeating the same commands can be error‑prone. Create a Makefile (or a simple shell script) that handles certificate generation, trust installation, and server launch.

    # Makefile
    CERT_DIR=certs
    KEY=$(CERT_DIR)/localdev.key
    CRT=$(CERT_DIR)/localdev.crt
    
    generate:
    \topenssl genrsa -out $(KEY) 2048
    \topenssl req -new -key $(KEY) -out $(CERT_DIR)/localdev.csr -subj "/CN=localhost"
    \topenssl x509 -req -days 365 -in $(CERT_DIR)/localdev.csr -signkey $(KEY) -out $(CRT)
    
    trust-mac:
    \topen -a "Keychain Access" $(CRT)
    \t# Manual steps required – see guide above
    
    run-flask:
    \tpython flask_app.py
    
    run-django:
    \tpython manage.py runserver_plus 8443 --cert-file $(CRT) --key-file $(KEY)
    
    run-fastapi:
    \tuvicorn main:app --host 127.0.0.1 --port 8443 --ssl-keyfile $(KEY) --ssl-certfile $(CRT)
    

    Now you can simply run make generate run-flask to spin up a secure Flask server in one line.

    Step 5: Testing HTTPS Locally

    After your server is up, verify the TLS handshake with tools you already trust:

    • Browser: Open https://localhost:8443 and check the lock icon.
    • cURL: curl -v https://localhost:8443 should show SSL connection using TLS without certificate errors.
    • OpenSSL: openssl s_client -connect localhost:8443 -servername localhost displays the certificate chain.

    Common Pitfalls and How to Fix Them

    Browser Still Shows “Not Secure”

    • Make sure the certificate’s CN (Common Name) matches the hostname you’re using (localhost or a custom .local domain).
    • Double‑check that the certificate is added to the correct trust store (system vs. user).
    • Clear cached HSTS entries: in Chrome, go to chrome://net-internals/#hsts and delete the domain.

    Port Conflicts

    HTTPS typically runs on 443. On a development machine that port is often occupied by Docker, Kubernetes, or other services. Use an alternative like 8443 or 3000 and configure your client applications accordingly.

    “SSL_ERROR_SYSCALL” Errors

    These usually indicate the server closed the connection unexpectedly. Verify that the paths to .crt and .key are correct and that the files have proper read permissions.

    Advanced Topics

    Using mkcert for Hassle‑Free Certificates

    If you prefer a tool that automatically creates trusted certificates, mkcert is a great alternative. Install it, then run:

    mkcert -install
    mkcert localhost 127.0.0.1 ::1
  • Python Web Security Best Practices Guide

    When you build a web application with Python, security isn’t an after‑thought – it’s a core part of the development lifecycle. From handling user input to configuring the deployment environment, every layer can become a target for attackers if you don’t follow proven best practices. This guide walks you through the most critical Python web security measures, offering practical code examples, configuration tips, and a checklist you can apply to Flask, Django, FastAPI, or any other Python framework.

    Why Python Web Security Matters

    Python’s popularity in web development stems from its readability and the rich ecosystem of frameworks and libraries. However, that same popularity makes Python applications a frequent target for common web attacks such as SQL injection, cross‑site scripting (XSS), and insecure deserialization. By embedding security into your code, testing, and deployment processes, you protect both your users and your brand reputation.

    Secure Coding Foundations

    1. Validate and Sanitize All Input

    • Never trust client data. Use schema validation libraries like pydantic (FastAPI) or marshmallow (Flask) to enforce type, length, and format constraints.
    • Strip or escape characters that could be interpreted as code, especially in HTML contexts.
    • Prefer whitelist validation (allowed values) over blacklist (blocked values).
    from pydantic import BaseModel, EmailStr, validator
    
    class RegistrationForm(BaseModel):
        username: str
        email: EmailStr
        password: str
    
        @validator('username')
        def username_alphanumeric(cls, v):
            assert v.isalnum(), 'Username must be alphanumeric'
            return v
    

    2. Use Parameterized Queries Everywhere

    Hard‑coded string concatenation in SQL statements is the classic cause of injection attacks. All major Python database drivers support parameterized queries.

    # Bad – vulnerable to SQL injection
    cursor.execute(f"SELECT * FROM users WHERE email = '{email}'")
    
    # Good – safe parameter binding
    cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
    

    3. Escape Output for the Correct Context

    Different output contexts require different escaping strategies:

    • HTML: Use the templating engine’s auto‑escaping (Jinja2, Django templates).
    • JavaScript: JSON‑encode data or use a safe templating function.
    • SQL: Parameterized queries (see above).
    • Shell commands: Avoid building command strings; use subprocess.run with a list of arguments.

    Framework‑Specific Security Features

    Django

    • CSRF Protection: Enabled by default. Ensure {% csrf_token %} is present in all POST forms.
    • Clickjacking Defense: Add X-Frame-Options: SAMEORIGIN via SECURE_BROWSER_XSS_FILTER = True and SECURE_CONTENT_TYPE_NOSNIFF = True in settings.py.
    • Password Hashing: Use Django’s built‑in make_password and check_password which default to PBKDF2 with a SHA256 hash.

    Flask

    • CSRF Tokens: Install Flask-WTF and add csrf = CSRFProtect(app).
    • Secure Cookies: Set SESSION_COOKIE_HTTPONLY = True and SESSION_COOKIE_SAMESITE = 'Lax' in the config.
    • Content Security Policy (CSP): Use Flask-Talisman to inject CSP headers automatically.

    FastAPI

    • Dependency Injection for Security: Leverage Depends with OAuth2 or API key schemes.
    • Automatic Validation: Pydantic models validate request bodies out of the box.
    • HTTPS Enforcement: Deploy behind a reverse proxy (e.g., Nginx) that redirects HTTP to HTTPS.

    Authentication and Authorization Best Practices

    Use Strong Password Hashing

    Never store plain‑text passwords. The argon2-cffi library provides Argon2, the winner of the 2015 Password Hashing Competition, and is recommended over older algorithms.

    from argon2 import PasswordHasher
    
    ph = PasswordHasher()
    hashed = ph.hash("SuperSecretPassword123!")
    # To verify:
    ph.verify(hashed, "SuperSecretPassword123!")
    

    Implement Multi‑Factor Authentication (MFA)

    Integrate time‑based one‑time passwords (TOTP) using pyotp or third‑party services like Auth0. MFA dramatically reduces the risk of credential stuffing.

    Principle of Least Privilege (PoLP)

    • Assign users the minimum role needed to perform their tasks.
    • Use Django’s django-guardian or Flask’s Flask-Principal for object‑level permissions.

    Secure Session Management

    • HTTPOnly & Secure Flags: Ensure cookies are marked HttpOnly and Secure to prevent JavaScript access and transmission over plain HTTP.
    • SameSite Attribute: Set SameSite=Lax or Strict to mitigate CSRF attacks.
    • Session Expiration: Define reasonable PERMANENT_SESSION_LIFETIME (e.g., 30 minutes of inactivity).

    Transport Layer Security (TLS)

    All production traffic must be encrypted with TLS 1.2 or higher. Follow these steps:

    1. Obtain a certificate from a trusted CA (Let’s Encrypt is free and automated).
    2. Configure your web server (Nginx, Apache, or Caddy) to enforce HTTPS and redirect all HTTP requests.
    3. Enable HTTP Strict Transport Security (HSTS) with a max‑age of at least 6 months:
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;
    

    Content Security Policy (CSP) and Other Headers

    Security‑related HTTP headers add layers of defense against XSS, clickjacking, and MIME‑type sniffing.

    • CSP: Define trusted sources for scripts, styles, and media.
    • X‑Content‑Type‑Options: nosniff prevents browsers from guessing MIME types.
    • Referrer‑Policy: Controls how much referrer information is sent with requests.
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.jsdelivr.net; object-src 'none';";
    add_header X-Content-Type-Options "nosniff";
    add_header Referrer-Policy "no-referrer-when-downgrade";
    

    Secure Dependency Management

    Pin Versions and Use Virtual Environments

    Never install packages globally. Use venv or pipenv and pin exact versions in requirements.txt or Pipfile.lock. Example:

    # requirements.txt
    Django==4.2.7
    django-axes==6.1.0
    cryptography==42.0.1
    

    Automated Vulnerability Scanning

    • Bandit: Static analysis tool for Python security issues.
    • Safety: Checks installed dependencies against known CVEs.
    • GitHub Dependabot: Opens pull requests when new security patches are released.

    Logging, Monitoring, and Incident Response

    • Structured Logging: Use structlog or the built‑in logging module with JSON output for easy ingestion by SIEM tools.
    • Audit Trails: Record authentication attempts, privilege changes, and data‑export actions.
    • Rate Limiting: Deploy django-ratelimit or Flask‑Limiter to thwart brute‑force attacks.
    • Alerting: Integrate with services like Sentry, Prometheus + Alertmanager, or CloudWatch to receive real‑time security alerts.

    Secure Deployment Practices

    Container Hardening

    • Base images: Use official python:3.12-slim or Alpine images with minimal attack surface.
    • Run as non‑root: Add a dedicated user in the Dockerfile.
    • Drop unnecessary capabilities and set readOnlyRootFilesystem: true in Kubernetes.

    Configuration Management

    Never hard‑code secrets. Store API keys, database passwords, and JWT secrets in environment variables or secret managers (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault). Example with python-decouple:

    
    
  • Python Multi-Factor Authentication Mfa Setup

    In today’s security‑first world, relying on just a password is no longer enough to protect your applications. Implementing multi‑factor authentication (MFA) in Python not only raises the bar against credential stuffing and phishing attacks, but also builds trust with users who expect modern, robust protection. This guide walks you through the concepts, tools, and step‑by‑step code you need to set up MFA—whether you’re building a Django web app, a Flask API, or a simple command‑line utility.

    Why MFA Matters for Python Applications

    Multi‑factor authentication adds at least one additional verification layer beyond the traditional username and password. The most common factors are:

    • Something you know – a password or PIN.
    • Something you have – a time‑based one‑time password (TOTP) generated by an authenticator app, a hardware token, or an SMS code.
    • Something you are – biometric data such as fingerprint or facial recognition.

    By requiring two or more of these factors, you dramatically reduce the attack surface. For Python developers, integrating MFA can be done with a handful of well‑maintained libraries, making it both secure and maintainable.

    Core Components of a Python MFA System

    1. Secret Key Generation

    Every user needs a unique secret key that will be shared between the server and the authenticator app. The secret is usually a base‑32 string, compliant with the HOTP and TOTP standards.

    2. QR Code Delivery

    To make enrollment user‑friendly, you generate a QR code that encodes the secret key along with the account name and issuer. Scanning the QR code with Google Authenticator, Authy, or any TOTP app adds the token automatically.

    3. Verification Logic

    When a user logs in, you validate the TOTP code they provide against the secret stored on the server. A small time window (usually ±30 seconds) is allowed to accommodate clock drift.

    4. Backup & Recovery Options

    Because users can lose access to their authenticator device, it’s best practice to offer backup codes, email OTP, or SMS fallback. This ensures a smooth user experience without compromising security.

    Choosing the Right Python Libraries

    The Python ecosystem offers several mature packages for MFA. Below is a quick comparison:

    • PyOTP – Implements HOTP/TOTP according to RFC 4226/6238. Simple, well‑documented, and works with any framework.
    • qrcode – Generates QR codes in PNG or SVG format, perfect for embedding in HTML emails or web pages.
    • django-otp – A Django‑specific solution that integrates with the authentication middleware and supports multiple OTP devices.
    • Flask-User – Extends Flask‑Login with optional two‑factor support.
    • python-jose – If you prefer JWT‑based MFA, this library helps sign and verify tokens.

    Step‑by‑Step MFA Setup in a Flask Application

    Prerequisites

    • Python 3.9+ installed.
    • Flask, PyOTP, and qrcode libraries (`pip install flask pyotp qrcode[pil]`).
    • A basic Flask app with user registration and login already in place.

    1. Extend the User Model

    # models.py
    from flask_sqlalchemy import SQLAlchemy
    
    db = SQLAlchemy()
    
    class User(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False)
        password_hash = db.Column(db.String(128), nullable=False)
        # New fields for MFA
        mfa_enabled = db.Column(db.Boolean, default=False)
        mfa_secret = db.Column(db.String(32))   # Base‑32 secret
        # Optional: store backup codes as a JSON list
        backup_codes = db.Column(db.Text)  # JSON‑encoded list
    

    2. Generate a Secret and QR Code During Enrollment

    # mfa.py
    import pyotp
    import qrcode
    import io
    import base64
    
    def generate_mfa_secret():
        # 16‑character base32 secret (80‑bit security)
        return pyotp.random_base32()
    
    def get_qr_code_uri(username, secret, issuer_name="MyFlaskApp"):
        totp = pyotp.TOTP(secret)
        return totp.provisioning_uri(name=username, issuer_name=issuer_name)
    
    def create_qr_image(uri):
        img = qrcode.make(uri)
        buffer = io.BytesIO()
        img.save(buffer, format="PNG")
        base64_img = base64.b64encode(buffer.getvalue()).decode()
        return f"data:image/png;base64,{base64_img}"
    

    3. Enrollment Route

    @app.route('/enroll-mfa', methods=['GET', 'POST'])
    @login_required
    def enroll_mfa():
        if request.method == 'POST':
            # User confirms they have scanned the QR code
            token = request.form.get('token')
            if pyotp.TOTP(current_user.mfa_secret).verify(token):
                current_user.mfa_enabled = True
                db.session.commit()
                flash('MFA enabled successfully!', 'success')
                return redirect(url_for('dashboard'))
            flash('Invalid token, try again.', 'danger')
        else:
            # First visit – generate secret & QR
            if not current_user.mfa_secret:
                current_user.mfa_secret = generate_mfa_secret()
                db.session.commit()
            uri = get_qr_code_uri(current_user.username, current_user.mfa_secret)
            qr_data = create_qr_image(uri)
            return render_template('enroll_mfa.html', qr_data=qr_data)
    

    4. Login Flow with MFA Challenge

    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            user = User.query.filter_by(username=request.form['username']).first()
            if user and check_password_hash(user.password_hash, request.form['password']):
                if user.mfa_enabled:
                    session['pre_mfa_user_id'] = user.id
                    return redirect(url_for('mfa_challenge'))
                login_user(user)
                return redirect(url_for('dashboard'))
            flash('Invalid credentials', 'danger')
        return render_template('login.html')
    
    @app.route('/mfa-challenge', methods=['GET', 'POST'])
    def mfa_challenge():
        user_id = session.get('pre_mfa_user_id')
        if not user_id:
            return redirect(url_for('login'))
        user = User.query.get(user_id)
        if request.method == 'POST':
            token = request.form.get('token')
            if pyotp.TOTP(user.mfa_secret).verify(token):
                login_user(user)
                session.pop('pre_mfa_user_id')
                return redirect(url_for('dashboard'))
            flash('Invalid MFA code', 'danger')
        return render_template('mfa_challenge.html')
    

    5. Generating Backup Codes (Optional)

    import secrets
    import json
    
    def generate_backup_codes(count=10):
        codes = [secrets.token_hex(4) for _ in range(count)]
        return json.dumps(codes)
    
    # Store once during enrollment
    current_user.backup_codes = generate_backup_codes()
    db.session.commit()
    

    Implementing MFA in Django with django‑otp

    If you’re using Django, the django‑otp package provides a plug‑and‑play solution that works with the default authentication system.

    1. Install the package: pip install django-otp django-two-factor-auth
    2. Add to INSTALLED_APPS:
      INSTALLED_APPS = [
          # …
          'django_otp',
          'django_otp.plugins.otp_totp',
          'two_factor',
      ]
    3. Update URLs:
      from django.urls import path, include
      
      urlpatterns = [
          # …
          path('account/', include('two_factor.urls', 'two_factor')),
      ]
    4. Run migrations:
      python manage.py migrate
    5. Enable MFA per user via the admin panel or programmatically:
      from django_otp.plugins.otp_totp.models import TOTPDevice
      
      device = TOTPDevice.objects.create(user=user, name='default')
      device.save()
      

    django‑otp automatically handles token verification, QR code generation, and backup token storage, letting you focus on the user experience.

    Best Practices for Secure MFA Implementation

    • Never store plain‑text secrets. Encrypt the mfa_secret column using a server‑side key or a dedicated secrets manager.
    • Limit verification attempts. Block the account or introduce exponential back‑off after 5–10 failed MFA attempts.
    • Use HTTPS everywhere. MFA codes are time‑sensitive; exposing them over plain HTTP defeats the purpose.
    • Provide clear recovery flows. Offer backup codes, email OTP, or SMS as secondary methods, but treat them with the same security level as primary tokens.
    • Log MFA events. Record successful and failed MFA challenges with timestamps, IP addresses, and user agents for audit trails
  • Python Password Reset Via Email Tutorial

    Are you looking for a reliable way to let users reset their forgotten passwords via email in a Python web application? In this step‑by‑step tutorial, we’ll walk you through everything you need—from setting up an SMTP server to generating secure tokens and updating passwords safely. Whether you’re building a Flask micro‑service or a full‑featured Django site, the concepts and code snippets below will give you a solid foundation for a production‑ready password‑reset flow.

    Why a Proper Password‑Reset Flow Matters

    Implementing a password‑reset feature isn’t just a convenience; it’s a security requirement. A well‑designed flow protects against:

    • Brute‑force attacks on reset tokens.
    • Phishing attempts that exploit poorly crafted emails.
    • Account takeover when tokens are leaked or reused.

    By following best practices—such as using time‑limited, cryptographically signed tokens—you’ll keep both your users and your application safe.

    Prerequisites and Tools

    Before diving into the code, make sure you have the following ready:

    1. Python 3.8+ installed on your development machine.
    2. A virtual environment (recommended venv or conda).
    3. Flask (or Django) installed—this tutorial uses Flask for simplicity.
    4. An SMTP service (Gmail, SendGrid, Mailgun, or a local smtp server).
    5. Basic knowledge of HTML forms and HTTP methods.

    Project Setup

    1. Create a fresh Flask project

    mkdir flask_password_reset
    cd flask_password_reset
    python -m venv venv
    source venv/bin/activate   # Windows: venv\Scripts\activate
    pip install Flask Flask-Mail itsdangerous
    

    2. Directory structure

    .
    ├── app.py
    ├── config.py
    ├── templates/
    │   ├── reset_request.html
    │   ├── reset_token.html
    │   └── email_template.html
    └── models.py   # simple user storage (SQLite for demo)
    

    Configuring Email with Flask‑Mail

    Flask‑Mail abstracts the SMTP details and lets you send HTML emails with just a few lines of code.

    # config.py
    MAIL_SERVER = 'smtp.gmail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = 'your.email@example.com'
    MAIL_PASSWORD = 'your‑app‑password'   # Use an app‑specific password!
    MAIL_DEFAULT_SENDER = ('YourApp Support', MAIL_USERNAME)
    
    # Secret key for signing tokens
    SECRET_KEY = 'a‑very‑strong‑random‑string‑replace‑this'
    

    Generating Secure Reset Tokens

    We’ll use the itsdangerous library, which ships with Flask, to create time‑limited, signed tokens.

    # models.py (simplified user model)
    from itsdangerous import URLSafeTimedSerializer
    from config import SECRET_KEY
    
    def generate_reset_token(email):
        serializer = URLSafeTimedSerializer(SECRET_KEY)
        return serializer.dumps(email, salt='password-reset-salt')
    
    def verify_reset_token(token, expiration=3600):
        serializer = URLSafeTimedSerializer(SECRET_KEY)
        try:
            email = serializer.loads(
                token,
                salt='password-reset-salt',
                max_age=expiration
            )
        except Exception:
            return None
        return email
    

    Building the Reset Request Form

    The first step in the user journey is a form where the user enters their email address.

    # templates/reset_request.html
    <!DOCTYPE html>
    <html>
    <body>
        <h2>Forgot Your Password?</h2>
        <form method="POST" action="/reset-request">
            <label for="email">Enter your email:</label><br>
            <input type="email" name="email" id="email" required><br><br>
            <button type="submit">Send Reset Link</button>
        </form>
    </body>
    </html>
    

    Handling the Reset Request in Flask

    # app.py
    from flask import Flask, render_template, request, flash, redirect, url_for
    from flask_mail import Mail, Message
    from models import generate_reset_token, verify_reset_token
    import sqlite3
    
    app = Flask(__name__)
    app.config.from_pyfile('config.py')
    mail = Mail(app)
    
    def get_user_by_email(email):
        conn = sqlite3.connect('users.db')
        cur = conn.cursor()
        cur.execute('SELECT id, email FROM users WHERE email = ?', (email,))
        user = cur.fetchone()
        conn.close()
        return user
    
    @app.route('/reset-request', methods=['GET', 'POST'])
    def reset_request():
        if request.method == 'POST':
            email = request.form['email']
            user = get_user_by_email(email)
            if user:
                token = generate_reset_token(email)
                reset_url = url_for('reset_token', token=token, _external=True)
                # Send email
                msg = Message('Password Reset for YourApp',
                              recipients=[email])
                msg.html = render_template('email_template.html', reset_url=reset_url)
                mail.send(msg)
                flash('A password reset link has been sent to your email.', 'info')
            else:
                flash('If the email exists in our system, a reset link will be sent.', 'info')
            return redirect(url_for('reset_request'))
        return render_template('reset_request.html')
    

    Designing the Reset Email Template

    # templates/email_template.html
    <p>Hello,</p>
    <p>We received a request to reset your password. Click the link below to choose a new password. This link will expire in 1 hour.</p>
    <p><a href="{{ reset_url }}" style="background:#4CAF50;color:#fff;padding:10px 15px;text-decoration:none;">Reset My Password</a></p>
    <p>If you didn’t request a password reset, you can safely ignore this email.</p>
    <p>Thanks,<br>YourApp Team</p>
    

    Creating the Password‑Reset Form

    When the user clicks the link, they’ll land on a page where they can set a new password.

    # templates/reset_token.html
    <!DOCTYPE html>
    <html>
    <body>
        <h2>Set a New Password</h2>
        <form method="POST" action="{{ url_for('reset_token', token=token) }}">
            <label for="password">New Password:</label><br>
            <input type="password" name="password" id="password" required><br><br>
            <label for="confirm">Confirm Password:</label><br>
            <input type="password" name="confirm" id="confirm" required><br><br>
            <button type="submit">Update Password</button>
        </form>
    </body>
    </html>
    

    Processing the New Password

    # app.py (continued)
    def update_user_password(email, new_password):
        # In a real app, hash the password with bcrypt or Argon2
        hashed = new_password  # placeholder; replace with proper hashing
        conn = sqlite3.connect('users.db')
        cur = conn.cursor()
        cur.execute('UPDATE users SET password = ? WHERE email = ?', (hashed, email))
        conn.commit()
        conn.close()
    
    @app.route('/reset/', methods=['GET', 'POST'])
    def reset_token(token):
        email = verify_reset_token(token)
        if not email:
            flash('The reset link is invalid or has expired.', 'danger')
            return redirect(url_for('reset_request'))
    
        if request.method == 'POST':
            pwd = request.form['password']
            confirm = request.form['confirm']
            if pwd != confirm:
                flash('Passwords do not match.', 'warning')
                return render_template('reset_token.html', token=token)
            # TODO: add password strength validation here
            update_user_password(email, pwd)
            flash('Your password has been updated. You can now log in.', 'success')
            return redirect(url_for('login'))   # assume a login route exists
        return render_template('reset_token.html', token=token)
    

    Security Best Practices

    Even though the code above works, production deployments should follow these extra safeguards:

    • Hash passwords securely using bcrypt, argon2-cffi, or passlib. Never store plain‑text passwords.
    • Rate‑limit reset requests per IP or per user to mitigate enumeration attacks.
    • Use HTTPS for every endpoint, especially the reset link.
    • Log token usage for audit trails, but never log the
  • Python Github Oauth Authentication Flow

    When you build a Python app that talks to GitHub—whether it’s a personal dashboard, a CI/CD tool, or a community‑driven bot—securely identifying users is a must. The most reliable way to do that is by leveraging GitHub’s OAuth 2.0 implementation. In this guide we’ll walk through the complete Python GitHub OAuth authentication flow, from registering your app on GitHub to exchanging the authorization code for an access token and finally calling the GitHub API. You’ll also get ready‑to‑run code snippets for Flask and Django, best‑practice security tips, and troubleshooting tricks that keep your integration smooth and SEO‑friendly.

    Understanding OAuth 2.0 and GitHub

    What is OAuth 2.0?

    OAuth 2.0 is an open standard for delegated authorization. Instead of handling passwords, a client application redirects the user to an authorization server (GitHub) where the user grants limited permissions—called scopes—to the client. After consent, the server redirects back with an authorization code, which the client exchanges for an access token. The token is then used in API calls, keeping the user’s credentials out of your codebase.

    Why GitHub uses OAuth

    GitHub’s API protects private repositories, organization data, and user actions. By using OAuth, GitHub ensures that third‑party apps only receive the permissions the user explicitly approves. This model also lets you revoke access at any time from the GitHub settings page, providing an extra layer of safety for both developers and end users.

    Prerequisites for a Python Implementation

    • Python 3.8+ installed on your development machine.
    • A GitHub account to register the OAuth application.
    • Either Flask or Django installed (the examples use Flask, but the flow is identical for Django).
    • The requests library for HTTP calls: pip install requests.
    • Optional: python‑dotenv for managing .env files securely.

    Step‑by‑Step Python GitHub OAuth Flow

    1. Register Your Application on GitHub

    Navigate to GitHub Settings → Developer settings → OAuth Apps → New OAuth App and fill in:

    1. Application name – e.g., “My Python Dashboard”.
    2. Homepage URL – the public URL of your app (or http://localhost:5000 for local testing).
    3. Authorization callback URL – the endpoint that will receive the code, such as http://localhost:5000/callback.

    After saving, GitHub provides a Client ID and a Client Secret**. Store these securely; never commit them to source control.

    2. Build the Authorization URL

    The first user‑facing step is to redirect the user to GitHub’s authorization endpoint. The URL must include:

    https://github.com/login/oauth/authorize?
    client_id=YOUR_CLIENT_ID
    &redirect_uri=YOUR_CALLBACK_URL
    &scope=repo,user
    &state=RANDOM_STRING

    Key parameters:

    • client_id – your app’s public identifier.
    • redirect_uri – must match the URL registered with GitHub.
    • scope – a space‑separated list of permissions (e.g., repo for private repo access, user for profile data).
    • state – a cryptographically random string to prevent CSRF attacks; store it in the user’s session and verify it on callback.

    3. Handle the Callback and Exchange Code for a Token

    When the user authorizes, GitHub redirects to your /callback endpoint with code and state query parameters. Verify the state value, then POST the following to https://github.com/login/oauth/access_token:

    POST https://github.com/login/oauth/access_token
    Headers:
      Accept: application/json
    Body (application/x-www-form-urlencoded):
      client_id=YOUR_CLIENT_ID
      client_secret=YOUR_CLIENT_SECRET
      code=AUTHORIZATION_CODE
      redirect_uri=YOUR_CALLBACK_URL
      state=STATE_VALUE

    The response contains a JSON object with access_token, token_type (always “bearer”), and the granted scope. Store the token securely—preferably in a server‑side session or a signed JWT.

    4. Use the Access Token to Call the GitHub API

    All subsequent GitHub API requests include the token in the Authorization header:

    GET https://api.github.com/user
    Headers:
      Authorization: Bearer YOUR_ACCESS_TOKEN
      Accept: application/vnd.github.v3+json

    Typical use cases include fetching the authenticated user’s profile, listing repositories, or creating issues. Remember to respect rate limits (5000 requests per hour per token) and handle 403 responses gracefully.

    5. Refresh Tokens and Revoking Access (GitHub specifics)

    GitHub does not issue refresh tokens; access tokens are long‑lived until the user revokes them. To programmatically revoke a token, send a DELETE request to https://api.github.com/applications/:client_id/token with basic auth using the Client ID and Client Secret. This is useful for “Logout” functionality.

    Sample Code with Flask

    import os
    import secrets
    from urllib.parse import urlencode

    import requests
    from flask import Flask, redirect, request, session, url_for, render_template_string
    from dotenv import load_dotenv

    load_dotenv() # Loads CLIENT_ID, CLIENT_SECRET from .env

    app = Flask(__name__)
    app.secret_key = os.urandom(24) # Needed for session handling

    GITHUB_AUTH_URL = "https://github.com/login/oauth/authorize"
    GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token"
    GITHUB_API_URL = "https://api.github.com"

    @app.route("/")
    def index():
    user = session.get("github_user")
    if user:
    return render_template_string(
    "

    Logged in as {{login}}

    "
    "

    Logout

    ", login=user["login"]
    )
    return render_template_string(
    "

    Welcome! Login with GitHub

    "
    )

    @app.route("/login")
    def login():
    state = secrets.token_urlsafe(16)
    session["oauth_state"] = state
    params = {
    "client_id": os.getenv("CLIENT_ID"),
    "redirect_uri": url_for("callback", _external=True),
    "scope": "repo user",
    "state": state,
    }
    return redirect(f"{GITHUB_AUTH_URL}?{urlencode(params)}")

    @app.route("/callback")
    def callback():
    # Verify state to mitigate CSRF
    if request.args.get("state") != session.get("oauth_state"):
    return "State mismatch", 400

    code = request.args.get("code")
    token_resp = requests.post(
    GITHUB_TOKEN_URL,
    headers={"Accept": "application/json"},
    data={
    "client_id": os.getenv("CLIENT_ID"),
    "client_secret": os.getenv("CLIENT_SECRET"),
    "code": code,
    "redirect_uri": url_for("callback", _external=True),
    "state": session["oauth_state"],
    },
    )
    token_resp.raise_for_status()
    access_token = token_resp.json()["access_token"]

    # Fetch user profile
    user_resp = requests.get(
    f"{GITHUB_API_URL}/user",
    headers={"Authorization": f"Bearer {access_token}", "Accept": "application/vnd.github.v3+json"},
    )
    user_resp

  • Python Google Oauth2 Login Integration

    Integrating Google OAuth 2.0 into a Python web application is one of the most effective ways to offer a seamless, secure, and familiar login experience for users. In this guide we’ll walk through every step—from creating credentials in the Google Cloud Console to writing clean, production‑ready Python code—so you can add “Sign in with Google” to your Flask or Django project in minutes. By the end of the article you’ll understand the OAuth 2.0 flow, how to verify ID tokens, and best practices for keeping your implementation safe and SEO‑friendly.

    Why Choose Google OAuth 2.0 for Python Applications?

    • Trusted identity provider: Over 2 billion users already have Google accounts, reducing friction and boosting conversion rates.
    • Reduced password fatigue: Users never need to create or remember another password, which lowers support tickets.
    • Built‑in security: Google handles password storage, multi‑factor authentication, and suspicious‑login detection.
    • Rich user profile data: Access to email, name, profile picture, and locale with a single API call.
    • SEO advantage: Faster login leads to lower bounce rates, longer session duration, and higher rankings for user‑centric signals.

    Prerequisites Before You Start

    1. A Google account with access to the Google Cloud Console.
    2. Python 3.8+ installed on your development machine.
    3. Basic familiarity with either Flask or Django (the examples cover both).
    4. Virtual environment tools such as venv or pipenv.

    Step 1: Create OAuth 2.0 Credentials in Google Cloud Console

    1.1 Enable the Google Identity Services API

    Navigate to APIs & Services > Library and search for Google Identity Services. Click Enable to activate the API for your project.

    1.2 Configure the OAuth consent screen

    • Go to APIs & Services > OAuth consent screen.
    • Select External (unless you’re building an internal app).
    • Fill in the required fields: App name, Support email, and Authorized domains.
    • Add the scopes you’ll request, e.g., openid, email, profile.
    • Save and continue; you can skip optional sections for a quick setup.

    1.3 Generate a client ID and client secret

    Under Credentials click Create credentials > OAuth client ID. Choose Web application** and set the following:

    • Authorized JavaScript origins: http://localhost:5000 (or your production domain).
    • Authorized redirect URIs: http://localhost:5000/auth/callback (Flask) or http://localhost:8000/accounts/google/login/callback/ (Django).

    Copy the Client ID and Client secret**; you’ll need them in your Python code.

    Step 2: Install Required Python Packages

    python -m venv venv
    source venv/bin/activate   # Windows: venv\Scripts\activate
    pip install Flask==2.3.*   # or Django==5.0.*
    pip install google-auth google-auth-oauthlib google-auth-httplib2 requests
    

    The google-auth family handles token verification, while requests is used for optional profile calls.

    Step 3: Implement the OAuth Flow in Flask

    3.1 Basic Flask app skeleton

    from flask import Flask, redirect, url_for, request, session, jsonify
    import os
    import google.auth.transport.requests
    from google.oauth2 import id_token
    
    app = Flask(__name__)
    app.secret_key = os.urandom(24)
    
    # Load credentials from environment variables for security
    GOOGLE_CLIENT_ID = os.getenv('GOOGLE_CLIENT_ID')
    GOOGLE_CLIENT_SECRET = os.getenv('GOOGLE_CLIENT_SECRET')
    REDIRECT_URI = 'http://localhost:5000/auth/callback'
    

    3.2 Build the authorization URL

    from urllib.parse import urlencode
    
    @app.route('/login')
    def login():
        params = {
            'client_id': GOOGLE_CLIENT_ID,
            'redirect_uri': REDIRECT_URI,
            'response_type': 'code',
            'scope': 'openid email profile',
            'access_type': 'offline',
            'prompt': 'consent'   # forces a refresh token on first login
        }
        auth_url = f"https://accounts.google.com/o/oauth2/v2/auth?{urlencode(params)}"
        return redirect(auth_url)
    

    3.3 Handle the callback and exchange the code for tokens

    import requests
    
    @app.route('/auth/callback')
    def callback():
        error = request.args.get('error')
        if error:
            return f"Error: {error}", 400
    
        code = request.args.get('code')
        token_endpoint = 'https://oauth2.googleapis.com/token'
        data = {
            'code': code,
            'client_id': GOOGLE_CLIENT_ID,
            'client_secret': GOOGLE_CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'
        }
        token_response = requests.post(token_endpoint, data=data)
        token_response.raise_for_status()
        tokens = token_response.json()
        id_info = verify_id_token(tokens['id_token'])
        session['user'] = {
            'sub': id_info['sub'],
            'email': id_info['email'],
            'name': id_info.get('name'),
            'picture': id_info.get('picture')
        }
        return redirect(url_for('profile'))
    

    3.4 Verify the ID token securely

    def verify_id_token(token):
        request_adapter = google.auth.transport.requests.Request()
        try:
            id_info = id_token.verify_oauth2_token(
                token,
                request_adapter,
                GOOGLE_CLIENT_ID
            )
            return id_info
        except ValueError as e:
            # Token is invalid
            raise RuntimeError(f"Invalid token: {e}")
    

    3.5 Display a simple profile page

    @app.route('/profile')
    def profile():
        user = session.get('user')
        if not user:
            return redirect(url_for('login'))
        return f"""
        

    Welcome, {user['name']}!

    Profile picture

    Email: {user['email']}

    Logout """

    3.6 Add a logout route

    @app.route('/logout')
    def logout():
        session.clear()
        return redirect(url_for('login'))
    

    Step 4: Django Integration (Alternative)

    4.1 Install Django‑allauth for a turnkey solution

    pip install django-allauth
    

    Allauth abstracts most of the OAuth boilerplate. Add the following to settings.py:

    INSTALLED_APPS = [
        # default Django apps …
        'django.contrib.sites',
        'allauth',
        'allauth.account',
        'allauth.socialaccount',
        'allauth.socialaccount.providers.google',
    ]
    
    SITE_ID = 1
    
    AUTHENTICATION_BACKENDS = [
        'django.contrib.auth.backends.ModelBackend',
        'allauth.account.auth_backends.AuthenticationBackend',
    ]
    
    LOGIN_REDIRECT_URL = '/'
    SOCIALACCOUNT_PROVIDERS = {
        'google': {
            'SCOPE': ['profile', 'email'],
            'AUTH_PARAMS': {'access_type': 'offline'},
            'APP': {
                'client_id': os.getenv('GOOGLE_CLIENT_ID'),
                'secret': os.getenv('GOOGLE_CLIENT_SECRET'),
                'key': ''
            }
        }
    }
    

    Include the URLs in urls.py:

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

    Run migrations and start the server. Users can now sign in via /accounts/login/ and select the Google button automatically rendered by Allauth.

    Step 5: Secure Your OAuth Implementation

    • Never hard‑code secrets: Store GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in environment variables or a secret manager.
    • Validate the state parameter: Include a cryptographically random state token in the auth request and verify it on callback to protect against CSRF attacks.
    • Use HTTPS in production: Google blocks insecure redirect URIs, and browsers flag mixed‑content warnings.
    • Limit token scopes: Request only the data you need (e.g., email and profile
  • Python Web App Rate Limiting With Redis

    When you build a Python web application that serves thousands—or even millions—of requests, protecting your API from abuse is essential. Rate limiting is the go‑to strategy for throttling traffic, preventing denial‑of‑service attacks, and ensuring a fair usage policy for all users. Among the many back‑ends you can choose, Redis stands out for its speed, atomic operations, and built‑in data structures that make implementing robust rate limits both simple and scalable. In this post we’ll explore why Redis is ideal for rate limiting, walk through several popular algorithms, and provide ready‑to‑use code snippets for Flask, Django, and FastAPI.

    Why Use Redis for Rate Limiting?

    Redis offers a unique blend of features that make it perfect for throttling requests in real time:

    • In‑memory speed: Sub‑millisecond latency ensures your rate‑limit checks don’t become a bottleneck.
    • Atomic commands: Operations like INCR, EXPIRE, and Lua scripts run atomically, eliminating race conditions in high‑concurrency environments.
    • TTL support: Expiration times let you automatically reset counters without extra cleanup logic.
    • Distributed safety: Multiple web workers can share the same Redis instance, guaranteeing consistent limits across a cluster.
    • Rich data structures: Sorted sets, hashes, and strings enable sophisticated algorithms such as sliding windows or token buckets.

    Choosing the Right Rate‑Limiting Algorithm

    Not every algorithm fits every use case. Below are the three most common patterns you can implement with Redis, along with their trade‑offs.

    1. Fixed Window Counter

    The simplest approach: count requests in a fixed time bucket (e.g., per minute). If the count exceeds the allowed threshold, reject the request.

    • Pros: Easy to understand, minimal Redis commands.
    • Cons: Bursts at bucket boundaries can exceed the limit (known as the “thundering herd” problem).

    2. Sliding Window Log

    Store timestamps of each request in a sorted set and prune entries older than the window. This yields a true sliding window behavior.

    • Pros: Precise enforcement; no burst spikes.
    • Cons: Higher memory usage and more Redis operations per request.

    3. Token Bucket (or Leaky Bucket)

    Maintain a bucket that refills at a steady rate. Each request consumes a token; if the bucket is empty, the request is throttled.

    • Pros: Allows short bursts while preserving an average rate.
    • Cons: Slightly more complex logic, but still a perfect fit for Redis Lua scripts.

    Implementing Fixed Window Counter in Flask

    Below is a minimal Flask middleware that limits each IP address to 100 requests per minute using Redis.

    from flask import Flask, request, jsonify
    import redis
    import time
    
    app = Flask(__name__)
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    
    LIMIT = 100          # requests
    WINDOW = 60          # seconds
    
    def is_allowed(ip):
        key = f"rl:{ip}"
        # Increment the counter and set expiry if this is the first hit
        current = r.incr(key)
        if current == 1:
            r.expire(key, WINDOW)
        return current <= LIMIT
    
    @app.before_request
    def rate_limit():
        ip = request.remote_addr
        if not is_allowed(ip):
            return jsonify({"error": "Rate limit exceeded"}), 429
    
    @app.route('/')
    def hello():
        return "Hello, world!"
    
    if __name__ == '__main__':
        app.run()
    

    This example demonstrates the core Redis commands (INCR and EXPIRE) that keep the implementation atomic and fast.

    Sliding Window Log with Redis Sorted Sets (Django)

    Django developers can leverage a custom middleware that uses a sorted set (ZSET) to store request timestamps. The following snippet shows how to limit a user (identified by user.id) to 20 actions per 10 seconds.

    import time
    import redis
    from django.utils.deprecation import MiddlewareMixin
    from django.http import JsonResponse
    
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    
    class SlidingWindowRateLimitMiddleware(MiddlewareMixin):
        LIMIT = 20
        WINDOW = 10  # seconds
    
        def process_request(self, request):
            if not request.user.is_authenticated:
                return  # skip unauthenticated users or handle differently
    
            user_key = f"rl:user:{request.user.id}"
            now = int(time.time() * 1000)  # milliseconds
    
            # Add current timestamp to the sorted set
            r.zadd(user_key, {now: now})
            # Remove entries older than the window
            r.zremrangebyscore(user_key, 0, now - self.WINDOW * 1000)
    
            # Get the count of timestamps in the window
            count = r.zcard(user_key)
            # Set a TTL so the key eventually disappears
            r.expire(user_key, self.WINDOW + 1)
    
            if count > self.LIMIT:
                return JsonResponse(
                    {"error": "Too many requests"},
                    status=429
                )
    

    Because ZADD, ZREMRangeByScore, and ZCARD are executed sequentially, you should wrap them in a Lua script for absolute atomicity in a production environment. The next section shows exactly that.

    Atomic Token Bucket with a Redis Lua Script (FastAPI)

    FastAPI’s async nature pairs nicely with Redis’ aioredis client. The Lua script below implements a token bucket that refills at rate tokens per second and allows up to capacity tokens.

    import asyncio
    from fastapi import FastAPI, Request, HTTPException
    import aioredis
    
    app = FastAPI()
    redis = None
    
    TOKEN_BUCKET_SCRIPT = """
    local key = KEYS[1]
    local capacity = tonumber(ARGV[1])
    local refill_rate = tonumber(ARGV[2])
    local now = tonumber(ARGV[3])
    
    -- Get the current bucket state
    local data = redis.call('HMGET', key, 'tokens', 'timestamp')
    local tokens = tonumber(data[1]) or capacity
    local timestamp = tonumber(data[2]) or now
    
    -- Refill tokens based on elapsed time
    local elapsed = now - timestamp
    local refill = elapsed * refill_rate
    tokens = math.min(capacity, tokens + refill)
    
    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 and 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
    """
    
    @app.on_event("startup")
    async def startup():
        global redis
        redis = await aioredis.create_redis_pool('redis://localhost')
    
    @app.on_event("shutdown")
    async def shutdown():
        redis.close()
        await redis.wait_closed()
    
    async def is_allowed(client_id: str, capacity: int = 10, rate: float = 1.0) -> bool:
        now = int(asyncio.get_event_loop().time())
        result = await redis.eval(
            TOKEN_BUCKET_SCRIPT,
            keys=[f"rl:bucket:{client_id}"],
            args=[capacity, rate, now]
        )
        return bool(result)
    
    @app.middleware("http")
    async def rate_limit(request: Request, call_next):
        client_id = request.headers.get("X-API-Key", request.client.host)
        allowed = await is_allowed(client_id, capacity=10, rate=1.0)  # 10 req/min
        if not allowed:
            raise HTTPException(status_code=429, detail="Rate limit exceeded")
        response = await call_next(request)
        return response
    
    @app.get("/")
    async def root():
        return {"message": "Welcome to a fast, rate‑limited API!"}
    

    Because the entire logic lives inside a Lua script, the check is atomic—even under heavy concurrency. Adjust capacity and rate to suit your API’s SLA.

    Best Practices for Production‑Ready Rate Limiting

    1. Centralize configuration: Keep limits (requests per window, burst size, etc.) in a single config file or environment variables so you can change them without redeploying code.
    2. Use consistent keys: Prefix keys (e.g., rl:user:, rl:ip:) to avoid collisions with other Redis data.
    3. Monitor Redis health: Rate limiting adds write load; set up alerts for latency, memory usage, and eviction events.
    4. Graceful degradation: When Redis is unavailable, decide whether to fail open (allow traffic) or fail closed (reject traffic). A common pattern is to let a limited “fallback” bucket operate locally for a short window.
    5. Cache static limits: If you have per‑plan limits (free vs. premium), cache the plan data in Redis or in‑process memory to avoid extra DB lookups on every request.
    6. Log throttled attempts: Recording rejected requests helps you spot abusive patterns and fine‑tune limits.

    Testing Your Rate Limiter

    Before shipping, verify that the limiter

  • Python Cors Configuration Guide

    Cross‑Origin Resource Sharing (CORS) can feel like a hidden gatekeeper for modern web applications, especially when you’re building APIs with Python. If you’ve ever seen a “No ‘Access‑Control‑Allow‑Origin’ header” error in your browser console, you know how frustrating it can be. This guide walks you through everything you need to know to configure CORS correctly in Python—whether you’re using Flask, Django, FastAPI, or a custom WSGI setup. By the end, you’ll have a solid, SEO‑friendly foundation to keep your APIs secure, performant, and ready for any front‑end client.

    What is CORS and Why It Matters in Python Web Apps

    Cross‑Origin Resource Sharing (CORS) is a browser security feature that restricts web pages from making requests to a different domain than the one that served the page. While this protects users from malicious sites, it also blocks legitimate API calls unless the server explicitly permits them.

    In Python web development, CORS configuration is essential for:

    • Enabling single‑page applications (SPAs) built with React, Vue, or Angular to communicate with a Python back‑end.
    • Allowing mobile apps, IoT devices, or third‑party services to consume your API.
    • Preventing accidental data leaks by restricting which origins can access sensitive endpoints.

    Getting CORS right improves both user experience and security posture, making it a non‑negotiable part of any production‑grade Python API.

    Core Principles of CORS Configuration

    Before diving into code, understand the four main CORS response headers that control access:

    • Access-Control-Allow-Origin – Specifies which origins are allowed.
    • Access-Control-Allow-Methods – Lists HTTP methods (GET, POST, etc.) the client may use.
    • Access-Control-Allow-Headers – Declares which custom headers the client can send.
    • Access-Control-Allow-Credentials – Indicates whether cookies or HTTP authentication are permitted.

    Origins

    The Origin header sent by the browser tells the server where the request originated. You can respond with a single origin (e.g., https://example.com) or a wildcard (*) for open access. Use wildcards sparingly; they bypass the security benefits of CORS.

    Methods

    Only expose the HTTP methods your API truly needs. Over‑exposing methods can invite unintended side effects. A typical safe list includes:

    GET, POST, PUT, PATCH, DELETE, OPTIONS

    Headers

    If your client sends custom headers like Authorization or X-Requested-With, you must list them in Access-Control-Allow-Headers. Otherwise the browser will block the request before it reaches your Python code.

    Credentials

    When you need to send cookies or HTTP authentication tokens across origins, set Access-Control-Allow-Credentials: true. Remember: you cannot use the wildcard (*) for the origin when credentials are allowed.

    Implementing CORS in Popular Python Frameworks

    Flask

    Flask’s lightweight nature makes it a perfect candidate for adding CORS via the flask-cors extension. Install it first:

    pip install flask-cors

    Then apply it globally or to specific blueprints:

    from flask import Flask
    from flask_cors import CORS
    
    app = Flask(__name__)
    
    # Global CORS with a whitelist
    CORS(app, resources={
        r"/api/*": {
            "origins": ["https://frontend.example.com", "https://admin.example.com"],
            "methods": ["GET", "POST", "PUT", "DELETE"],
            "allow_headers": ["Content-Type", "Authorization"],
            "supports_credentials": True
        }
    })
    
    @app.route('/api/data')
    def data():
        return {"message": "CORS is configured!"}
    

    Django

    Django users typically rely on django-cors-headers. Install and add it to your project:

    pip install django-cors-headers

    Update settings.py:

    # settings.py
    INSTALLED_APPS = [
        # …
        'corsheaders',
        # …
    ]
    
    MIDDLEWARE = [
        'corsheaders.middleware.CorsMiddleware',
        'django.middleware.common.CommonMiddleware',
        # …
    ]
    
    # Allow specific origins only
    CORS_ALLOWED_ORIGINS = [
        "https://frontend.example.com",
        "https://admin.example.com",
    ]
    
    CORS_ALLOW_METHODS = [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "DELETE",
    ]
    
    CORS_ALLOW_HEADERS = [
        "content-type",
        "authorization",
    ]
    
    CORS_ALLOW_CREDENTIALS = True
    

    FastAPI

    FastAPI, built on Starlette, includes built‑in CORS middleware. Add it during app creation:

    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_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        allow_headers=["*"],  # Adjust as needed
        allow_credentials=True,
    )
    
    @app.get("/api/items")
    async def read_items():
        return {"message": "FastAPI CORS setup complete"}
    

    Advanced CORS Strategies

    For larger projects, static whitelists may not be enough. Consider these advanced techniques to keep your Python CORS configuration flexible and secure.

    Dynamic Origin Validation

    Instead of a hard‑coded list, you can check the incoming Origin against a database or environment variable at runtime. Example for Flask:

    from flask import request
    from flask_cors import cross_origin
    
    def is_allowed_origin(origin):
        # Example: fetch from DB or config service
        allowed = {"https://frontend.example.com", "https://admin.example.com"}
        return origin in allowed
    
    @app.route("/api/secure")
    @cross_origin(origin= lambda: request.headers.get("Origin") if is_allowed_origin(request.headers.get("Origin")) else "")
    def secure_endpoint():
        return {"status": "dynamic CORS applied"}
    

    Environment‑Specific Settings

    Use separate CORS configurations for development, staging, and production. Store each set in environment variables (e.g., CORS_ORIGINS_DEV) and load them at startup. This prevents accidental exposure of production data during testing.

    Fine‑Grained Path Control

    Apply different CORS rules per endpoint. For instance, a public read‑only endpoint can use a wildcard origin, while a private /admin route requires strict origin and credential checks. Both Flask and Django support per‑route decorators or view‑level settings.

    Cache CORS Preflight Responses

    Browsers send an OPTIONS preflight request before the actual request. To reduce latency, set Access-Control-Max-Age (e.g., 86400 seconds) so the browser caches the permission for a day.

    Testing and Debugging CORS

    Even with perfect code, misconfigurations happen. Follow this checklist to verify your CORS setup:

    1. Use browser dev tools. Look for the Access-Control-Allow-* headers in the Network tab.
    2. Test with curl. Example: curl -i -H "Origin: https://frontend.example.com" -X GET http://api.example.com/api/data should return the appropriate CORS headers.
    3. Check preflight handling. Ensure the OPTIONS route returns 200 and includes all required headers.
    4. Validate credentials. When Access-Control-Allow-Credentials: true is set, confirm the Access-Control-Allow-Origin is not a wildcard.
    5. Automate with integration tests. Tools like pytest combined with requests can assert header presence programmatically.

    If you encounter “CORS policy: No ‘Access‑Control‑Allow‑Origin’ header is present” errors, double‑check that the origin string exactly matches the one in your whitelist (including protocol and port).

  • Python Csrf Protection In Web Applications

    Cross‑Site Request Forgery (CSRF) remains one of the most common yet misunderstood security threats facing modern web applications. Even though the attack vector is simple—tricking a logged‑in user into sending an unwanted request—its impact can be devastating, from unauthorized data changes to full account takeover. Fortunately, Python’s rich ecosystem provides robust, battle‑tested tools to defend against CSRF. In this guide we’ll explore the theory behind CSRF, walk through best‑practice implementation in popular Python frameworks, and share practical tips to keep your web apps safe without sacrificing developer productivity.

    Understanding CSRF: The Attack in Plain English

    Before you can protect your application, you need to understand how CSRF works. The attacker exploits the trust a browser has in a user’s session cookies. By embedding a malicious link, image tag, or form on a third‑party site, the attacker forces the victim’s browser to send an authenticated request to your server—often without the user realizing it.

    • Victim is logged in: The user’s session cookie is automatically attached to every request to your domain.
    • Malicious site triggers a request: A hidden form or JavaScript call submits data to your endpoint.
    • Server processes the request: Because the cookie is valid, the server assumes the request is legitimate.

    Since the attacker cannot read the response (due to the Same‑Origin Policy), they rely on side‑effects—such as changing a password, posting a comment, or initiating a financial transaction—to achieve their goal.

    Why CSRF Tokens Are the Gold Standard

    CSRF tokens are unique, unpredictable values generated by the server and tied to a user’s session. When a form is rendered, the token is embedded as a hidden field (or as a request header for AJAX calls). The server then validates the token on every state‑changing request. If the token is missing, expired, or mismatched, the request is rejected.

    Key properties of a good CSRF token:

    • Unpredictable: Must be generated using a cryptographically secure random source.
    • Per‑session or per‑request: Either tied to the user session or regenerated for each form.
    • Bound to the user: The token should be stored server‑side (e.g., in the session) so it cannot be forged.

    Implementing CSRF Protection in Django

    Django ships with built‑in CSRF protection that works out of the box for most use cases. The framework automatically adds a hidden csrfmiddlewaretoken field to every <form> rendered with the {% csrf_token %} template tag.

    Step‑by‑step setup

    1. Enable the middleware: Ensure 'django.middleware.csrf.CsrfViewMiddleware' is listed in MIDDLEWARE in settings.py.
    2. Add the token to templates:
      {% raw %}
      
      {% csrf_token %}
      {% endraw %}
    3. Validate in views: For function‑based views, use @csrf_exempt only when you have a good reason; otherwise, Django validates automatically.
    4. Handle AJAX requests: Include the token in the X‑CSRFToken header.
      $.ajax({
          type: "POST",
          url: "/api/update/",
          data: JSON.stringify(payload),
          contentType: "application/json",
          beforeSend: function(xhr) {
              xhr.setRequestHeader("X-CSRFToken", "{{ csrf_token }}");
          }
      });

    When a request fails validation, Django returns a 403 Forbidden response with a helpful error page. You can customize this behavior by overriding CsrfViewMiddleware.process_view or providing a custom 403.html template.

    Common pitfalls

    • Disabling the middleware globally (@csrf_exempt) defeats the protection.
    • Using csrf_exempt on API endpoints that accept cookies; prefer token‑based authentication (e.g., JWT) for stateless APIs.
    • Forcing the token into GET requests—CSRF tokens should only protect state‑changing (POST, PUT, DELETE, PATCH) methods.

    CSRF Defense in Flask

    Flask does not include CSRF protection by default, but the Flask‑WTF extension makes it straightforward. Flask‑WTF integrates wtforms with CSRF handling and stores the token in the session.

    Quick start guide

    1. Install the extension: pip install Flask-WTF
    2. Configure the secret key:
      app = Flask(__name__)
      app.config['SECRET_KEY'] = 'a-very-secret-key'
    3. Create a form class:
      from flask_wtf import FlaskForm
      from wtforms import StringField, SubmitField
      
      class CommentForm(FlaskForm):
          comment = StringField('Comment')
          submit = SubmitField('Post')
    4. Render the form in a template:
      {% raw %}
      
      {{ form.hidden_tag() }} {{ form.comment.label }} {{ form.comment() }} {{ form.submit() }}
      {% endraw %}
    5. Validate in the view:
      @app.route('/comment', methods=['GET', 'POST'])
      def comment():
          form = CommentForm()
          if form.validate_on_submit():
              # process comment
              flash('Comment posted!')
              return redirect(url_for('index'))
          return render_template('comment.html', form=form)

    Flask‑WTF automatically checks the token on every POST request. If the token is missing or invalid, a 400 Bad Request error is raised.

    CSRF for API‑only endpoints

    When building a JSON‑based API that does not use server‑side sessions, you should consider one of the following strategies:

    • Stateless tokens: Use a double‑submit cookie pattern where the client reads a cookie named csrf_token and sends it back in a custom header.
    • Header‑only protection: Require a custom header (e.g., X-CSRF-Token) that the client obtains via a prior authenticated request.
    • Switch to token‑based auth: JWT or OAuth2 eliminates the need for CSRF protection because the token is not automatically sent by the browser.

    CSRF Mitigation Techniques Beyond Tokens

    While tokens are the most widely adopted solution, a layered defense strategy can further reduce risk.

    SameSite Cookies

    Setting the SameSite attribute on session cookies tells browsers not to include the cookie on cross‑origin requests. Modern browsers support three values:

    • Strict: Cookie is sent only for same‑site navigation.
    • Lax: Cookie is sent for top‑level GET navigation but not for POST, PUT, etc. (good balance for most sites).
    • None: Cookie is sent on all requests; must be paired with Secure.

    In Django, you can enable it with:

    SESSION_COOKIE_SAMESITE = 'Lax'

    In Flask (using Flask-Session or directly on Response.set_cookie):

    response.set_cookie('session', value, samesite='Lax', secure=True)

    Content Security Policy (CSP)

    A strict CSP can prevent malicious scripts from loading on your pages, reducing the chance that an attacker can craft a forged request. Example header:

    Content-Security-Policy: default-src 'self'; script-src 'self' https://cdnjs.cloudflare.com;

    Enforce HTTP Referrer Checks (with caution)

    Some legacy systems also verify the Referer header to ensure the request originates from an allowed domain. This method is not recommended as a primary defense because the header can be stripped or spoofed, but it can serve as a supplemental check.

    Testing Your CSRF Implementation

    Automated tests should verify that legitimate requests succeed while forged requests are blocked. Below is a simple pytest example for a Flask app using Flask‑WTF.

    import pytest
    from app import app

    @pytest.fixture
    def client():
    app.config['WTF_CSRF_ENABLED'] = True
    with app.test_client() as client:
    yield client

    def test_valid_csrf(client):
    # Get the form to retrieve the token
    resp = client.get('/comment')
    token = re.search(r'name="csrf_token" value="([^"]+)"', resp.get_data(as_text=True)).group(1)

    # Submit with the token
    resp = client.post('/comment', data={'comment': 'test', 'csrf_token': token})
    assert resp.status_code == 302 # redirect on success

    def test_missing_csrf(client):
    resp = client.post('/comment', data={'comment': 'test'})

  • Python Web Session Management Best Practices

    Managing user sessions securely and efficiently is a cornerstone of any Python-powered web application. Whether you’re building a Flask micro‑service, a Django e‑commerce site, or a FastAPI data dashboard, the way you handle sessions can dramatically affect performance, scalability, and, most importantly, security. In this guide we’ll explore the best practices for Python web session management, covering everything from cookie configuration and server‑side storage to CSRF protection and session expiration strategies. By the end, you’ll have a clear roadmap to implement robust, SEO‑friendly session handling that keeps both users and your application safe.

    Why Session Management Matters for SEO and User Experience

    Search engines reward sites that provide a seamless, secure experience. Proper session handling helps:

    • Maintain user state across pages, reducing bounce rates.
    • Protect personal data from hijacking, which can lead to penalties or loss of trust.
    • Improve site speed by avoiding unnecessary database hits.
    • Enable personalized content that can boost dwell time and conversion rates.

    Core Principles of Secure Session Management

    1. Prefer Server‑Side Session Stores

    Storing session data on the client (e.g., in plain cookies) exposes it to tampering. Instead, keep only a signed session identifier on the client and store the actual data on the server.

    # Example using Flask with Redis as a server‑side store
    from flask import Flask, session
    from flask_session import Session
    import redis
    
    app = Flask(__name__)
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379')
    app.config['SESSION_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_SECURE'] = True
    Session(app)
    

    2. Use Strong, Random Session IDs

    Session identifiers must be cryptographically random to prevent session fixation attacks. Python’s secrets module is ideal for this purpose.

    import secrets
    
    def generate_session_id():
        return secrets.token_urlsafe(32)  # 256‑bit entropy
    

    3. Set Secure Cookie Attributes

    When you place the session ID in a cookie, configure these attributes:

    • HttpOnly: Prevents JavaScript from accessing the cookie.
    • Secure: Sends the cookie only over HTTPS.
    • SameSite: Mitigates CSRF; use Strict or Lax as appropriate.
    • Domain & Path: Scope the cookie to the minimal necessary domain/path.

    4. Implement Proper Session Expiration

    Two expiration strategies work together:

    1. Idle timeout – invalidate the session after a period of inactivity (e.g., 15 minutes).
    2. Absolute timeout – enforce a maximum lifespan regardless of activity (e.g., 24 hours).

    Both can be stored as timestamps in the server‑side session and refreshed on each request.

    5. Rotate Session IDs on Privilege Changes

    When a user logs in, upgrades privileges, or performs a sensitive action, regenerate the session ID to thwart fixation attacks.

    # Flask example: regenerate on login
    from flask import session, redirect, url_for
    
    def login_user(user):
        session.clear()                # Remove old data
        session['user_id'] = user.id
        session['csrf_token'] = generate_csrf()
        # Flask-Session will automatically issue a new cookie
        return redirect(url_for('dashboard'))
    

    Choosing the Right Session Backend for Your Framework

    Django

    Django ships with a robust session framework out of the box. By default it stores sessions in the database, but you can switch to cache‑based stores for better performance.

    • Database backend: Simple, persistent, but slower for high‑traffic sites.
    • Cache backend (Redis/Memcached): Fast, ideal for read‑heavy workloads.
    • Signed cookies: Useful for stateless apps, but limit data size and security.

    Example configuration for Redis:

    # settings.py
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
    SESSION_CACHE_ALIAS = 'default'  # Assuming CACHE setting points to Redis
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = True
    SESSION_COOKIE_SAMESITE = 'Lax'
    

    Flask

    Flask does not include a built‑in session store, but extensions like Flask-Session or itsdangerous make it easy to adopt server‑side storage.

    • Use Flask-Session with Redis or Memcached for scalability.
    • Leverage itsdangerous.URLSafeTimedSerializer for signed cookie sessions when you need a stateless approach.

    FastAPI

    FastAPI’s async nature pairs well with external stores. Common patterns include:

    • Storing a session token in a signed JWT (stateless) combined with a server‑side revocation list.
    • Using starlette.sessions with a backend like Redis via aioredis.
    # FastAPI example with starlette.sessions and Redis
    from fastapi import FastAPI, Request
    from starlette.middleware.sessions import SessionMiddleware
    import aioredis
    
    app = FastAPI()
    app.add_middleware(
        SessionMiddleware,
        secret_key="super-secret-key",
        max_age=86400,                # 24‑hour absolute timeout
        same_site="lax",
        https_only=True,
    )
    
    # Simple Redis client for server‑side storage
    redis = aioredis.from_url("redis://localhost")
    

    Protecting Sessions Against Common Attacks

    Cross‑Site Request Forgery (CSRF)

    Even with SameSite cookies, CSRF tokens remain a best practice, especially for state‑changing POST/PUT/DELETE requests.

    # Generate a CSRF token and store it in the session
    def generate_csrf():
        token = secrets.token_urlsafe(32)
        session['csrf_token'] = token
        return token
    
    # Validate on form submission
    def validate_csrf(request):
        token = request.form.get('csrf_token')
        return token == session.get('csrf_token')
    

    Session Hijacking

    Mitigate by:

    • Enforcing HTTPS (HSTS header).
    • Binding sessions to user‑agent or IP address (with caution for mobile networks).
    • Implementing short idle timeouts.

    Session Fixation

    Always regenerate the session ID after authentication and when elevating privileges, as shown earlier.

    Performance Tips for High‑Traffic Applications

    Use In‑Memory Caches for Session Reads

    Redis or Memcached can handle millions of read/write operations per second, keeping latency low.

    Avoid Storing Large Objects in Sessions

    Sessions should contain lightweight identifiers (user ID, roles, CSRF token). Large blobs increase memory usage and network overhead.

    Batch Session Cleanup

    Configure your backend to purge expired sessions automatically:

    • Redis: set expire on each session key.
    • PostgreSQL/Django: use clearsessions management command via cron.

    Testing and Auditing Your Session Implementation

    Regular security testing ensures that session handling remains airtight.

    1. Automated unit tests – Verify that session IDs rotate on login and that cookies contain the correct attributes.
    2. Penetration testing – Use tools like OWASP ZAP to probe for CSRF, XSS, and session fixation.
    3. Log monitoring – Track anomalous session activity (e.g., rapid IP changes).

    SEO‑Friendly Session Practices

    Search engines crawl pages anonymously, so session handling should not block indexing:

    • Never require a session for static content; serve assets without cookies.
    • Use rel="canonical" tags to avoid duplicate URLs caused by session query parameters.
    • Prefer URL‑based navigation for public pages; reserve sessions for authenticated or personalized sections.

    Sample End‑to‑End Implementation (Flask + Redis)

    from flask import Flask, session, request, redirect, url_for, render_template_string
    from flask_session import Session
    import redis, secrets, datetime

    app = Flask(__name__)
    app.config.update(
    SECRET_KEY=secrets.token_hex(16),
    SESSION_TYPE='redis',
    SESSION_REDIS=redis.from_url('redis://localhost:6379/0'),
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_SAMESITE='Lax',
    PERMANENT_SESSION_LIFETIME=datetime.timedelta(hours=24) # absolute timeout
    )
    Session(app)

    def generate_csrf():
    token = secrets.token_urlsafe(32)
    session['csrf_token'] = token
    return token

    @app.before_request
    def enforce_idle_timeout():
    now = datetime.datetime.utcnow()
    last = session.get('last_activity')
    if last and (now - last).seconds > 900: # 15‑minute idle timeout
    session.clear()
    return redirect(url_for('login'))
    session['last_activity'] = now

    @app.route('/login', methods=['GET', 'POST'])
    def login():
    if request.method == 'POST':
    # Authenticate user...
    session.clear()
    session['user_id'] = 42
    generate_csrf()
    return redirect(url_for('dashboard'))
    return render_template_string