Category: Uncategorized

  • Python Beautifulsoup Web Scraping Beginner Guide

    Welcome to the Python BeautifulSoup web scraping beginner guide! If you’ve ever wanted to extract data from websites but felt overwhelmed by the technical jargon, you’re in the right place. In this step‑by‑step tutorial we’ll cover everything a newcomer needs to know: installing BeautifulSoup, parsing HTML, navigating the DOM tree, handling common pitfalls, and best practices for ethical scraping. By the end, you’ll be able to write clean, maintainable scripts that pull exactly the information you need—whether it’s product prices, news headlines, or sports scores.

    Why Choose BeautifulSoup for Web Scraping?

    BeautifulSoup is a Python library designed to make HTML and XML parsing simple and intuitive. Here are a few reasons why it’s the go‑to tool for beginners:

    • Human‑readable API: Methods like find() and select() read like plain English.
    • Robust handling of malformed markup: Real‑world web pages often contain broken tags; BeautifulSoup cleans them up automatically.
    • Seamless integration: Works perfectly with requests, urllib, and even headless browsers such as Selenium.
    • Active community: Plenty of tutorials, Stack Overflow answers, and extensions (e.g., lxml parser) to boost performance.

    Getting Started: Installation and Setup

    Before writing any code, make sure you have Python (3.8+ recommended) installed on your system. Then install the required packages using pip:

    pip install beautifulsoup4 requests lxml

    The lxml parser is optional but significantly faster than the default Python parser. If you’re on Windows and encounter build errors, you can stick with the built‑in parser by omitting lxml.

    Creating a Virtual Environment (Optional but Recommended)

    • Open your terminal.
    • Run python -m venv bs4-env to create an isolated environment.
    • Activate it:
      • Windows: bs4-env\Scripts\activate
      • macOS/Linux: source bs4-env/bin/activate
    • Install the packages inside the environment.

    Fetching a Web Page with requests

    BeautifulSoup only parses HTML; it doesn’t download it. The requests library is the simplest way to fetch a page:

    import requests
    
    url = "https://example.com"
    response = requests.get(url)
    
    # Always check the status code
    if response.status_code == 200:
        html_content = response.text
    else:
        raise Exception(f"Failed to retrieve page: {response.status_code}")

    Tip: Use a User-Agent header to mimic a real browser and avoid being blocked:

    headers = {"User-Agent": "Mozilla/5.0 (compatible; MyScraper/1.0)"}
    response = requests.get(url, headers=headers)

    Parsing HTML with BeautifulSoup

    Now that you have the raw HTML, feed it into BeautifulSoup:

    from bs4 import BeautifulSoup
    
    soup = BeautifulSoup(html_content, "lxml")  # or "html.parser"

    The soup object represents the entire DOM tree, allowing you to search, filter, and extract data.

    Basic Navigation Techniques

    • Tag name: soup.title returns the <title> element.
    • Attributes: soup.a['href'] fetches the href attribute of the first link.
    • Text content: soup.get_text() returns all visible text.
    • Finding multiple elements: soup.find_all('div', class_='product').

    Using CSS Selectors with select()

    If you’re comfortable with CSS, select() offers a powerful shortcut:

    # Grab all headlines inside a news article
    headlines = soup.select('article h2.headline')
    for h in headlines:
        print(h.get_text(strip=True))

    Practical Example: Scraping a Simple E‑Commerce Site

    Let’s walk through a realistic scenario—extracting product names, prices, and URLs from a mock e‑commerce page.

    Step 1: Inspect the Page Structure

    Open the page in your browser, right‑click a product, and choose “Inspect”. You’ll notice each product is wrapped in a <div class="product-card"> with the following pattern:

    <div class="product-card">
        <a href="/product/123" class="product-link">
            <h3 class="product-name">Super Widget</h3>
        </a>
        <span class="price">$19.99</span>
    </div>

    Step 2: Write the Scraper

    import requests
    from bs4 import BeautifulSoup
    
    BASE_URL = "https://example-store.com"
    
    def fetch_page(page=1):
        url = f"{BASE_URL}/products?page={page}"
        headers = {"User-Agent": "Mozilla/5.0 (compatible; ScraperBot/1.0)"}
        resp = requests.get(url, headers=headers)
        resp.raise_for_status()
        return resp.text
    
    def parse_products(html):
        soup = BeautifulSoup(html, "lxml")
        product_cards = soup.select('div.product-card')
        products = []
        for card in product_cards:
            name_tag = card.select_one('h3.product-name')
            price_tag = card.select_one('span.price')
            link_tag = card.select_one('a.product-link')
            if not (name_tag and price_tag and link_tag):
                continue  # Skip malformed entries
            product = {
                "name": name_tag.get_text(strip=True),
                "price": price_tag.get_text(strip=True),
                "url": BASE_URL + link_tag['href']
            }
            products.append(product)
        return products
    
    if __name__ == "__main__":
        html = fetch_page()
        items = parse_products(html)
        for i, p in enumerate(items, 1):
            print(f"{i}. {p['name']} – {p['price']} – {p['url']}")

    This script demonstrates the core workflow: request → parse → extract → store.

    Handling Common Challenges

    1. Dealing with JavaScript‑Rendered Content

    BeautifulSoup can’t execute JavaScript. If the data you need loads dynamically, consider:

    • Using Selenium with a headless browser (Chrome/Firefox).
    • Inspecting the network tab to find the underlying API endpoint and calling it directly with requests.

    2. Pagination and Infinite Scroll

    Most sites split results across multiple pages. Identify the pagination pattern (e.g., ?page=2) and loop until you receive an empty result set or a “next” button disappears.

    3. Rate Limiting and Politeness

    • Respect robots.txt (use urllib.robotparser to parse it).
    • Introduce a delay between requests: time.sleep(random.uniform(1, 3)).
    • Use rotating proxies or user‑agents only if the site’s terms allow it.

    4. Dealing with Anti‑Scraping Measures

    CAPTCHAs, IP blocks, and honeypot fields can stop naive scrapers. Strategies include:

    • Switching to a residential proxy service.
    • Implementing session cookies from a logged‑in browser.
    • Leveraging services like ScraperAPI that handle challenges for you.

    Best Practices for Clean and Maintainable Code

    • Separate concerns: Keep networking, parsing, and data storage in distinct functions or modules.
    • Use data classes: Python’s @dataclass makes product objects easy to manage.
    • Log, don’t print: Replace print() with the logging module for better debugging and production readiness.
    • Write unit tests: Mock HTTP responses with responses or requests-mock to ensure your parser stays reliable when the site changes.
    • Document your code: Inline comments and docstrings help future you (or collaborators) understand the scraping logic.

    Storing Scraped Data

    Once you’ve extracted the information, you’ll likely want to persist it. Common options include:

    • CSV files: Simple and portable. Use csv.DictWriter for quick export.
    • JSON: Ideal for hierarchical data. json.dump() works out of the box.
    • Databases: SQLite for small projects, PostgreSQL or MySQL for larger pipelines. ORMs like SQLAlchemy simplify CRUD operations.

    Example: Saving to CSV

    import csv

    def save_to_csv(products, filename="products.csv"):
    fieldnames = ["name", "price", "url"]
    with open(filename, mode="w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f

  • Python Selenium Web Driver Complete Tutorial

    Welcome to the ultimate Python Selenium WebDriver complete tutorial! Whether you’re a seasoned developer looking to automate web testing or a beginner eager to dive into the world of browser automation, this guide will walk you through everything you need to know—from installing Selenium to mastering advanced techniques. By the end of this article, you’ll be able to write robust, maintainable scripts that interact with any modern web application, boost your testing efficiency, and unlock powerful automation possibilities.

    Why Choose Selenium with Python?

    Selenium remains the industry‑standard tool for web automation, and Python’s clean syntax makes it an ideal pairing. Here are a few reasons why this combo is a favorite among QA engineers and developers:

    • Cross‑browser support: Control Chrome, Firefox, Edge, Safari, and more.
    • Open source & community driven: Extensive documentation, plugins, and community‑contributed solutions.
    • Easy integration: Works seamlessly with testing frameworks like unittest, pytest, and CI/CD pipelines.
    • Scalable: From simple single‑page checks to complex end‑to‑end workflows.

    Getting Started: Installation & Setup

    1. Install Python (if you haven’t already)

    Download the latest stable version from python.org and follow the installer prompts. Ensure python and pip are added to your system PATH.

    2. Install Selenium via pip

    pip install selenium

    3. Download the appropriate WebDriver

    Selenium communicates with browsers through a driver executable. Choose the driver that matches your browser version:

    Place the driver binary in a folder that’s part of your system PATH or specify its location directly in your script.

    Writing Your First Selenium Script

    Let’s create a simple script that opens Google, searches for “Python Selenium tutorial”, and prints the page title.

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.common.keys import Keys
    import time
    
    # 1. Initialize the Chrome driver
    driver = webdriver.Chrome()  # Ensure chromedriver is in PATH
    
    try:
        # 2. Navigate to Google
        driver.get("https://www.google.com")
    
        # 3. Locate the search box, enter a query, and submit
        search_box = driver.find_element(By.NAME, "q")
        search_box.send_keys("Python Selenium tutorial")
        search_box.send_keys(Keys.RETURN)
    
        # 4. Wait for results to load
        time.sleep(2)
    
        # 5. Print the title of the results page
        print("Page title is:", driver.title)
    finally:
        # 6. Clean up
        driver.quit()

    This script demonstrates the core Selenium workflow: initialize driver → navigate → locate elements → interact → close. Feel free to run it and observe the browser automation in action.

    Essential Selenium Concepts

    Locating Elements

    Finding the right element is the backbone of any automation script. Selenium offers several strategies:

    • By.ID
    • By.NAME
    • By.XPATH
    • By.CSS_SELECTOR
    • By.CLASS_NAME
    • By.TAG_NAME
    • By.LINK_TEXT / By.PARTIAL_LINK_TEXT

    Example using CSS_SELECTOR:

    login_button = driver.find_element(By.CSS_SELECTOR, "button.login")

    Handling Waits

    Web pages often load elements asynchronously. Relying on time.sleep() is fragile; instead, use explicit or implicit waits.

    # Implicit wait – applies globally
    driver.implicitly_wait(10)
    
    # Explicit wait – waits for a specific condition
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    element = WebDriverWait(driver, 15).until(
        EC.presence_of_element_located((By.ID, "dynamic-element"))
    )

    Working with Multiple Windows & Tabs

    Automation may require switching contexts. Here’s a quick pattern:

    # Open a new tab
    driver.execute_script("window.open('https://www.example.com');")
    # Switch to the newly opened tab
    driver.switch_to.window(driver.window_handles[-1])
    # Perform actions, then return
    driver.close()
    driver.switch_to.window(driver.window_handles[0])

    Advanced Topics for Power Users

    1. Using Selenium Grid for Parallel Execution

    Selenium Grid lets you run tests across multiple browsers and machines simultaneously. Set up a hub and register nodes, then configure your test script to point to the hub URL:

    from selenium import webdriver
    
    grid_url = "http://localhost:4444/wd/hub"
    capabilities = {
        "browserName": "chrome",
        "platformName": "windows"
    }
    driver = webdriver.Remote(command_executor=grid_url, desired_capabilities=capabilities)

    2. Integrating with PyTest for Structured Testing

    Combine Selenium with pytest to get fixtures, parametrization, and detailed reports.

    # conftest.py
    import pytest
    from selenium import webdriver
    
    @pytest.fixture(scope="function")
    def driver():
        driver = webdriver.Chrome()
        yield driver
        driver.quit()
    
    # test_login.py
    def test_login(driver):
        driver.get("https://example.com/login")
        driver.find_element(By.ID, "username").send_keys("admin")
        driver.find_element(By.ID, "password").send_keys("secret")
        driver.find_element(By.ID, "submit").click()
        assert "Dashboard" in driver.title

    3. Capturing Screenshots & Logs

    When a test fails, a screenshot can save hours of debugging.

    driver.save_screenshot("error_snapshot.png")

    For deeper insight, retrieve browser console logs (Chrome only):

    logs = driver.get_log('browser')
    for entry in logs:
        print(entry)

    Best Practices to Keep Your Scripts Clean and Reliable

    • Use Page Object Model (POM): Separate page structure from test logic for maintainability.
    • Prefer explicit waits over static sleeps to handle dynamic content.
    • Keep selectors robust: Favor IDs or stable CSS classes; avoid brittle XPaths.
    • Parameterize data with fixtures or external files (CSV, JSON) to enable data‑driven testing.
    • Run headless mode in CI pipelines to speed up execution and avoid UI dependencies.

    Sample Page Object Model Implementation

    Below is a minimal POM structure for a login page.

    # pages/login_page.py
    from selenium.webdriver.common.by import By
    
    class LoginPage:
        def __init__(self, driver):
            self.driver = driver
            self.username_input = (By.ID, "username")
            self.password_input = (By.ID, "password")
            self.submit_button = (By.ID, "loginBtn")
    
        def load(self):
            self.driver.get("https://example.com/login")
    
        def login(self, username, password):
            self.driver.find_element(*self.username_input).send_keys(username)
            self.driver.find_element(*self.password_input).send_keys(password)
            self.driver.find_element(*self.submit_button).click()

    Running Your Tests in Headless Mode

    Headless browsers run without a graphical UI, perfect for CI environments.

    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    options = Options()
    options.add_argument("--headless")
    options.add_argument("--disable-gpu")
    driver = webdriver.Chrome(options=options)

    Common Pitfalls and How to Avoid Them

    1. Version mismatches: Always align the browser version with its driver.
    2. StaleElementReferenceException: Refresh element references after page reloads or dynamic DOM changes.
    3. Hard‑coded waits: Replace time.sleep() with explicit waits to reduce flakiness.
    4. Missing clean‑up: Ensure driver.quit() runs even when exceptions occur (use try/finally or fixtures).

    Conclusion

    Mastering the Python Selenium WebDriver equips you with a versatile toolkit for automating web interactions, accelerating test cycles, and improving overall software quality. By following the steps outlined in this tutorial—setting up the environment, writing clean scripts, leveraging advanced features like Selenium Grid and the Page Object Model, and adhering to best practices—you’ll be ready to tackle real‑world automation challenges with confidence. Keep experimenting, stay updated with Selenium’s latest releases, and let automation become a core strength of your development workflow.

  • Python Playwright Web Automation Guide

    If you’re looking to supercharge your web testing or scraping projects with a modern, reliable tool, Python Playwright is the answer. Built by the creators of Microsoft Edge, Playwright offers cross‑browser automation that’s faster, more stable, and easier to maintain than many legacy solutions. In this guide, we’ll walk you through everything you need to know—from installation to advanced techniques—so you can start automating the web with confidence.

    What Is Playwright and Why Choose It for Python?

    Playwright is an open‑source automation library that supports Chromium, Firefox, and WebKit with a single API. Its key advantages include:

    • Cross‑browser consistency: Write one script and run it on Chrome, Edge, Safari, and Firefox.
    • Auto‑wait mechanisms: No more flaky time.sleep() calls; Playwright waits for elements to become actionable.
    • Built‑in network interception: Mock responses, block ads, or capture traffic for debugging.
    • Headless and headed modes: Perfect for CI pipelines and local debugging alike.

    Because it’s designed for modern web apps, Playwright handles single‑page applications (SPAs), shadow DOM, and iframes out of the box—making it a top choice for Python developers.

    Getting Started: Installation and Project Setup

    1. Install Playwright with pip

    pip install playwright
    # Install the browsers (Chromium, Firefox, WebKit)
    python -m playwright install
    

    This single command downloads the necessary browser binaries, ensuring version compatibility.

    2. Create a Minimal Project Structure

    • tests/ – Store all automation scripts.
    • requirements.txt – List dependencies (e.g., playwright, pytest).
    • conftest.py – Optional fixtures for shared setup/teardown.

    3. Verify the Installation

    from playwright.sync_api import sync_playwright
    
    def run():
        with sync_playwright() as p:
            browser = p.chromium.launch(headless=False)
            page = browser.new_page()
            page.goto("https://example.com")
            print(page.title())
            browser.close()
    
    if __name__ == "__main__":
        run()
    

    Running this script should open a visible browser, navigate to example.com, print “Example Domain,” and close gracefully.

    Core Concepts and Basic Automation

    Launching Browsers and Contexts

    A browser represents the executable (Chromium, Firefox, WebKit). A browser context isolates cookies, storage, and permissions, allowing parallel sessions without interference.

    with sync_playwright() as p:
        # Launch Chromium in headless mode
        browser = p.chromium.launch(headless=True)
    
        # Create two independent contexts
        context1 = browser.new_context()
        context2 = browser.new_context()
    

    Page Interaction Basics

    • page.goto(url) – Navigate to a page.
    • page.click(selector) – Click an element.
    • page.fill(selector, text) – Type into input fields.
    • page.wait_for_selector(selector) – Explicit wait for an element.
    • page.screenshot(path="shot.png") – Capture a screenshot.

    Sample Login Flow

    def login(page, username, password):
        page.goto("https://demo-site.com/login")
        page.fill("#email", username)
        page.fill("#password", password)
        page.click("button[type='submit']")
        page.wait_for_selector("text=Dashboard")
    

    Advanced Playwright Features

    Network Interception and Mocking

    Intercepting requests lets you test edge cases without relying on external services.

    def mock_api(route, request):
        if "api/v1/data" in request.url:
            route.fulfill(
                status=200,
                content_type="application/json",
                body='{"mocked": true}'
            )
        else:
            route.continue_()
    
    with sync_playwright() as p:
        browser = p.chromium.launch()
        context = browser.new_context()
        page = context.new_page()
        page.route("**/*", mock_api)
        page.goto("https://myapp.com")
    

    Handling Dialogs, Frames, and Shadow DOM

    • Dialogs: page.on("dialog", lambda d: d.accept())
    • Frames: frame = page.frame(name="my-iframe")
    • Shadow DOM: Use page.locator("css=shadow-host >> css=inner-element")

    Taking Screenshots and Recording Videos

    These artifacts are invaluable for debugging CI failures.

    # Screenshot of a specific element
    page.locator("#profile-pic").screenshot(path="profile.png")
    
    # Video recording for an entire test
    context = browser.new_context(record_video_dir="videos/")
    page = context.new_page()
    page.goto("https://example.com")
    page.wait_for_timeout(2000)  # Let the page settle
    page.close()
    # Retrieve video path
    video_path = page.video.path()
    

    Parallel Execution with Pytest

    Combine Playwright with pytest and pytest-xdist for scalable test suites.

    # conftest.py
    import pytest
    from playwright.sync_api import sync_playwright
    
    @pytest.fixture(scope="session")
    def browser():
        with sync_playwright() as p:
            browser = p.chromium.launch()
            yield browser
            browser.close()
    
    # test_login.py
    def test_successful_login(browser):
        context = browser.new_context()
        page = context.new_page()
        # Reuse the login helper from earlier
        login(page, "user@example.com", "Secret123")
        assert page.is_visible("text=Welcome")
    

    Run with pytest -n auto to distribute tests across CPU cores.

    Integrating Playwright into CI/CD Pipelines

    Most CI platforms (GitHub Actions, GitLab CI, Azure Pipelines) support Docker, making Playwright integration straightforward.

    GitHub Actions Example

    name: Playwright Tests
    on: [push, pull_request]
    
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v3
          - name: Set up Python
            uses: actions/setup-python@v4
            with:
              python-version: "3.11"
          - name: Install dependencies
            run: |
              pip install -r requirements.txt
              python -m playwright install --with-deps
          - name: Run tests
            run: pytest -n auto --headless
    

    Best Practices for Reliable Automation

    • Prefer locators over raw selectors: page.get_by_role("button", name="Submit") is more resilient to UI changes.
    • Use explicit waits: Rely on page.wait_for_selector or built‑in auto‑wait instead of fixed sleeps.
    • Isolate tests with fresh contexts: Prevent state leakage between scenarios.
    • Store credentials securely: Use environment variables or secret managers, never hard‑code passwords.
    • Capture artifacts on failure: Screenshots, logs, and videos help pinpoint flaky behavior.

    Common Pitfalls and How to Avoid Them

    1. Ignoring Browser Version Mismatches

    Playwright bundles its own browsers, but if you manually install a system browser, version drift can cause unexpected errors. Stick to the bundled binaries unless you have a specific need.

    2. Overusing time.sleep()

    Static sleeps increase test runtime and cause flakiness. Replace them with page.wait_for_load_state() or element‑specific waits.

    3. Not Cleaning Up Resources

    Always close pages, contexts, and browsers. Using with sync_playwright() as p: ensures proper teardown even when exceptions occur.

    4. Missing Headless Configuration in CI

    CI environments often lack a display server. Explicitly launch browsers in headless mode or use playwright install-deps to add required libraries.

    Where to Learn More

    • Official documentation: playwright.dev/python
    • Playwright GitHub repository for community examples.
    • Video tutorials on YouTube (search “Python Playwright tutorial”).
    • Open‑source projects on GitHub that showcase real‑world test suites.

    Conclusion

    Python Playwright combines the power of modern browsers with a clean, Pythonic API, making it an ideal choice for anyone

  • Python Server-Sent Events Sse Web App

    Imagine a web application that pushes live data to users the instant something changes—no page reloads, no extra JavaScript libraries, just a simple, reliable stream. That’s the power of Server‑Sent Events (SSE) in Python. In this guide we’ll explore why SSE is a perfect fit for real‑time web apps, walk through a complete implementation using Flask (and a quick look at Django and FastAPI), and share best practices to keep your code clean, scalable, and SEO‑friendly.

    What Are Server‑Sent Events?

    Server‑Sent Events are a standard HTML5 technology that lets a server push text‑based updates to a browser over a single, long‑lived HTTP connection. Unlike WebSockets, SSE is unidirectional (server → client) and uses the simple text/event-stream MIME type, making it easy to implement and friendly to firewalls and proxies.

    Key Benefits of SSE

    • Simple API: Only the EventSource object is needed on the client side.
    • Automatic Reconnect: Browsers automatically retry lost connections.
    • Built‑in Heartbeat: Keep‑alive messages prevent idle timeouts.
    • SEO‑Friendly: Since the initial page is rendered server‑side, search engines can index content normally.
    • Low Overhead: No binary framing or handshake—just plain UTF‑8 text.

    When to Choose SSE Over WebSockets

    SSE shines in scenarios where you need real‑time updates but don’t require bi‑directional communication. Typical use‑cases include:

    1. Live sports scores or stock tickers.
    2. Chat notifications (not the chat messages themselves).
    3. Server health dashboards.
    4. Progress bars for long‑running background jobs.

    If your app needs client‑to‑server messaging (e.g., multiplayer games), WebSockets may be a better fit. For most notification‑style updates, SSE is the lighter, more maintainable choice.

    Setting Up a Basic SSE Endpoint with Flask

    Flask’s minimalistic design makes it a great playground for SSE. Below is a step‑by‑step example that streams random numbers to the browser every second.

    1. Install Required Packages

    pip install Flask
    

    2. Create the Flask Application

    from flask import Flask, Response, stream_with_context
    import time
    import random
    
    app = Flask(__name__)
    
    def generate_numbers():
        """Yield a new random number every second as an SSE message."""
        while True:
            # SSE format: "data: \n\n"
            yield f"data: {random.randint(1, 100)}\n\n"
            time.sleep(1)
    
    @app.route('/stream')
    def stream():
        # Use stream_with_context to keep the generator alive across requests
        return Response(stream_with_context(generate_numbers()),
                        mimetype='text/event-stream')
    
    @app.route('/')
    def index():
        return '''
        
        
          SSE Demo
          
            

    Random Numbers (SSE)

    ''' if __name__ == '__main__': app.run(debug=True, threaded=True)

    Key points to note:

    • The generate_numbers function yields strings in the SSE format (data: …\n\n).
    • Response with mimetype='text/event-stream' tells the browser to treat the output as an event stream.
    • Setting threaded=True (or using a production WSGI server) ensures each client gets its own connection.

    3. Run and Test

    Start the app with python app.py and navigate to http://localhost:5000. You should see a number updating every second without any page refresh.

    Scaling SSE with Production Servers

    While Flask’s built‑in server works for development, production environments need a robust WSGI server that supports streaming responses. Here are three popular choices:

    • Gunicorn: Use the gevent worker class for asynchronous I/O.
      gunicorn -k gevent -w 4 app:app
    • Uvicorn (ASGI): Ideal for FastAPI or Starlette apps, also works with Flask via asgiref.wsgi.WsgiToAsgi.
    • mod_wsgi (Apache): Configure WSGIApplicationGroup %{GLOBAL} to allow streaming.

    Regardless of the server, remember to enable HTTP/2 or HTTPS for better performance and security. Browsers still support SSE over HTTP/1.1, but TLS eliminates middle‑box interference.

    Implementing SSE in Django

    Django’s request/response cycle is synchronous by default, but with Django Channels you can serve SSE without leaving the Django ecosystem.

    Minimal Django SSE View

    # views.py
    from django.http import StreamingHttpResponse
    import time
    import random
    
    def sse_stream(request):
        def event_generator():
            while True:
                yield f"data: {random.randint(1, 100)}\n\n"
                time.sleep(1)
    
        response = StreamingHttpResponse(event_generator(),
                                         content_type='text/event-stream')
        response['Cache-Control'] = 'no-cache'
        return response
    

    Add the URL pattern:

    # urls.py
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('stream/', views.sse_stream, name='sse_stream'),
    ]
    

    Combine this with a standard Django template that includes the same EventSource JavaScript shown earlier, and you have a fully functional SSE endpoint inside a full‑featured web framework.

    FastAPI: Asynchronous SSE Made Easy

    FastAPI is built on Starlette, which natively supports asynchronous streaming. The following example demonstrates a non‑blocking SSE endpoint that pushes the server’s current timestamp every second.

    # main.py
    from fastapi import FastAPI
    from fastapi.responses import StreamingResponse
    import asyncio
    import datetime
    
    app = FastAPI()
    
    async def time_stream():
        while True:
            now = datetime.datetime.utcnow().isoformat()
            yield f"data: {now}\\n\\n"
            await asyncio.sleep(1)
    
    @app.get("/time")
    async def stream_time():
        return StreamingResponse(time_stream(),
                                 media_type="text/event-stream")
    

    Run with uvicorn main:app --reload and open http://localhost:8000/time in the browser. The timestamps will appear instantly, proving that asynchronous SSE scales efficiently with many concurrent connections.

    Advanced SSE Patterns

    Sending Custom Event Types

    Beyond the default message event, you can define custom event names using the event: field. This enables you to handle different payloads with distinct callbacks.

    # Python generator example
    def custom_events():
        while True:
            yield "event: price\\n"
            yield "data: 123.45\\n\\n"
            time.sleep(2)
    
            yield "event: alert\\n"
            yield "data: Threshold exceeded!\\n\\n"
            time.sleep(3)
    

    Client‑side handling:

    const source = new EventSource('/custom');
    source.addEventListener('price', e => console.log('Price:', e.data));
    source.addEventListener('alert', e => alert(e.data));
    

    Heartbeat / Keep‑Alive Messages

    Some proxies close idle connections after 30 seconds. Sending a comment line (:) every 15 seconds prevents this:

    def heartbeat():
        while True:
            yield ": keep-alive\\n\\n"
            time.sleep(15)
    

    Combine heartbeat with your data generator using itertools.chain or an async asyncio.gather loop.

    Authentication & Security

    • Token‑based auth: Verify a JWT or API key before returning the StreamingResponse. Reject unauthorized requests with 401.
    • CORS: Set Access-Control-Allow-Origin header if your frontend lives on a different domain.
    • Rate limiting: Use Redis or a middleware to cap the number of concurrent streams per user.

    Testing and Debugging SSE

    Because SSE is a streaming protocol, traditional request‑response testing tools (like curl) need the -N flag to disable buffering:

    curl -N http://localhost:5000/stream
    

    For automated tests, consider Requests with stream=True or use httpx.AsyncClient in an async test

  • Python Https Local Development Setup

    Developing web applications with Python often starts on a local machine, but as soon as you need to test OAuth callbacks, secure cookies, or third‑party APIs, plain HTTP quickly becomes a bottleneck. Setting up a reliable HTTPS local development environment not only mirrors production conditions but also eliminates “mixed‑content” warnings and keeps sensitive data encrypted even during debugging. In this guide we walk through everything you need—self‑signed certificates, tools like mkcert, framework‑specific configurations, and Docker tricks—so you can spin up a secure Python server in minutes.

    Why Use HTTPS for Local Development?

    • Security compliance: Modern browsers block insecure origins from accessing geolocation, camera, or payment APIs.
    • OAuth & SSO: Providers such as Google, GitHub, and Azure require a https:// redirect URI, even in dev.
    • Feature parity: Testing CSP, HSTS, and secure cookie flags works exactly as they will in production.
    • Future‑proofing: Once HTTPS is baked into your workflow, moving to a cloud host becomes a simple copy‑paste.

    Prerequisites

    • Python 3.8+ installed (virtual environments recommended)
    • OpenSSL (usually pre‑installed on macOS/Linux; Windows users can use Git Bash)
    • One of the following web frameworks: Flask, Django, FastAPI, or a plain http.server
    • Optional but highly recommended: mkcert for trusted local certificates

    Generating a Self‑Signed Certificate with OpenSSL

    If you prefer the classic approach, OpenSSL can create a certificate that browsers will accept after you add it to the trust store.

    Step‑by‑step commands

    # Create a private key
    openssl genrsa -out localhost.key 2048
    
    # Generate a certificate signing request (CSR)
    openssl req -new -key localhost.key -out localhost.csr \
        -subj "/C=US/ST=California/L=SanFrancisco/O=MyDev/CN=localhost"
    
    # Sign the certificate (valid for 365 days)
    openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt
    
    # Verify the pair
    openssl x509 -in localhost.crt -text -noout
    

    Place localhost.key and localhost.crt in a secure folder (e.g., certs/) and reference them in your Python server.

    Using mkcert for Trusted Local Certificates

    Self‑signed certificates trigger warnings unless you manually trust them. mkcert automates the process by creating a local CA and issuing certificates that browsers trust out of the box.

    Installation

    • macOS: brew install mkcert && brew install nss # for Firefox
    • Linux (Debian/Ubuntu): sudo apt install libnss3-tools then curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" and chmod +x mkcert
    • Windows: choco install mkcert or download the binary from the GitHub releases page.

    Creating the cert

    # Generate and install a local CA (run once)
    mkcert -install
    
    # Create a cert for localhost and any subdomains you need
    mkcert localhost 127.0.0.1 ::1
    

    This command produces localhost+2.pem (certificate) and localhost+2-key.pem (private key). They can be used directly with any Python server.

    Framework‑Specific HTTPS Configuration

    Flask

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def hello():
        return "Secure Flask!"
    
    if __name__ == '__main__':
        # For development only – use a production WSGI server in prod
        app.run(host='0.0.0.0', port=5000, ssl_context=('certs/localhost.crt', 'certs/localhost.key'))
    

    Django

    Django’s built‑in development server can serve HTTPS with the runsslserver package.

    # Install the helper
    pip install django-sslserver
    
    # Add to INSTALLED_APPS in settings.py
    INSTALLED_APPS += ['sslserver']
    
    # Run with SSL
    python manage.py runsslserver 0.0.0.0:8000 \
        --certificate certs/localhost.crt \
        --keyfile certs/localhost.key
    

    FastAPI / Uvicorn

    import uvicorn
    from fastapi import FastAPI
    
    app = FastAPI()
    
    @app.get("/")
    def read_root():
        return {"message": "Secure FastAPI"}
    
    if __name__ == "__main__":
        uvicorn.run(
            "main:app",
            host="0.0.0.0",
            port=8443,
            ssl_certfile="certs/localhost.crt",
            ssl_keyfile="certs/localhost.key",
        )
    

    Plain http.server (Python 3.7+)

    import http.server
    import ssl
    
    server_address = ('', 4443)
    httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
    
    # Wrap socket with SSL
    httpd.socket = ssl.wrap_socket(
        httpd.socket,
        server_side=True,
        certfile='certs/localhost.crt',
        keyfile='certs/localhost.key',
        ssl_version=ssl.PROTOCOL_TLS,
    )
    
    print("Serving HTTPS on port 4443")
    httpd.serve_forever()
    

    Dockerizing a Secure Python Service

    Containers add isolation, but they also require you to mount the certificates or build them inside the image.

    Dockerfile example (Flask)

    FROM python:3.12-slim
    
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install -r requirements.txt
    
    # Copy source and certs
    COPY . /app
    COPY certs/localhost.crt /etc/ssl/certs/
    COPY certs/localhost.key /etc/ssl/private/
    
    EXPOSE 5000
    
    CMD ["python", "app.py"]
    

    Run with:

    docker build -t secure-flask .
    docker run -p 5000:5000 secure-flask
    

    Testing Your HTTPS Setup

    • Browser test: Open https://localhost:5000 (or the port you chose). You should see a lock icon if the cert is trusted.
    • cURL verification: curl -vk https://localhost:5000 shows the TLS handshake details.
    • Postman / Insomnia: Import the same URL; these tools automatically trust mkcert certificates.

    Common Pitfalls & How to Fix Them

    • “CERTIFICATE_VERIFY_FAILED” errors: Ensure the CA generated by mkcert -install is in your system’s trust store. On Linux, you may need to update /etc/ssl/certs/ca-certificates.crt.
    • Port conflicts: Default HTTPS ports are 443, 8443, or 5001. Choose a free port and update firewall rules if needed.
    • Mixed‑content warnings: All assets (CSS, JS, images) must be loaded over https://. Use relative URLs or protocol‑agnostic // prefixes.
    • Docker networking: When using Docker Desktop, localhost inside the container refers to the container itself. Map ports correctly and use host.docker.internal for host‑to‑container communication.

    Automating Certificate Renewal

    Self‑signed certificates expire after a set period (often 365 days). Automate regeneration with a simple shell script or a Makefile target:

    # Makefile
    cert:
    \tmkcert -install
    \tmkcert localhost 127.0.0.1 ::1
    
    renew:
    \tmake cert
    

    Run make renew weekly via cron or Task Scheduler to keep the dev environment hassle‑free.

    SEO‑Friendly Keywords to Remember

    When you write documentation, blog posts, or README files, sprinkle these terms to improve discoverability:

    • Python HTTPS local development
    • self‑signed SSL certificate Python
    • mkcert Python tutorial
    • Flask HTTPS development server
    • Django SSL local setup
    • FastAPI HTTPS Docker
    • local OAuth callback HTTPS

    Conclusion

    Switching from plain HTTP to a fully functional HTTPS local development setup is no longer a daunting chore. Whether you rely on OpenSSL for a quick self‑signed pair or prefer the hassle‑free trust

  • Python Web Security Best Practices Guide

    Building a web application with Python is fast, flexible, and fun, but security can’t be an after‑thought. Whether you’re using Django, Flask, FastAPI, or a lightweight micro‑framework, a single vulnerability can expose user data, damage your brand, and lead to costly breaches. This guide walks you through the essential Python web security best practices you need to embed into every line of code, configuration file, and deployment step.

    Why Python Web Security Matters

    Python powers a huge share of modern web services, from startups to enterprise platforms. Its popularity makes it a frequent target for attackers looking for common pitfalls such as injection flaws, insecure authentication, and misconfigured servers. By adopting a security‑first mindset, you not only protect users but also improve code quality, maintainability, and compliance with regulations like GDPR and PCI‑DSS.

    Secure Coding Foundations

    1. Validate and Sanitize All Input

    • Never trust client data. Use libraries such as pydantic (FastAPI) or Django’s built‑in form validation to enforce type, length, and format constraints.
    • Apply a whitelist approach: define exactly what characters or patterns are allowed instead of trying to block known bad inputs.
    • For file uploads, verify MIME types, check file extensions, and store files outside the web root.

    2. Protect Against Injection Attacks

    SQL injection, command injection, and template injection are classic threats. Follow these rules:

    1. Always use parameterized queries or ORM methods. Example with psycopg2:
    cursor.execute(
        "SELECT * FROM users WHERE email = %s",
        (user_email,)
    )
    1. Never concatenate raw strings into SQL, shell commands, or template tags.
    2. Escape data when rendering user‑generated content in templates; Django’s auto‑escaping and Jinja2’s |e filter help.

    3. Implement Strong Authentication and Authorization

    • Prefer OAuth2/OpenID Connect or JSON Web Tokens (JWT) for stateless authentication.
    • Store passwords with argon2 or bcrypt via passlib; never use MD5, SHA1, or plain text.
    • Enforce multi‑factor authentication (MFA) for privileged accounts.
    • Apply the principle of least privilege: limit each user’s permissions to only what they need.

    Framework‑Specific Hardening

    Django Security Checklist

    • Use django-secure settings: SECURE_HSTS_SECONDS, SECURE_CONTENT_TYPE_NOSNIFF, SECURE_BROWSER_XSS_FILTER.
    • Set ALLOWED_HOSTS to your domain(s) only.
    • Enable CSRF_COOKIE_SECURE and SESSION_COOKIE_SECURE for HTTPS.
    • Activate X_FRAME_OPTIONS = 'DENY' to prevent click‑jacking.
    • Turn on django.middleware.security.SecurityMiddleware and django.middleware.clickjacking.XFrameOptionsMiddleware.

    Flask Security Essentials

    • Install Flask‑Talisman to add HTTP security headers (HSTS, CSP, X‑Content‑Type‑Options).
    • Use Flask‑Login with strong password hashing and session protection.
    • Never expose the secret key; load it from environment variables or a vault.
    • Validate request data with marshmallow or pydantic before processing.

    Data Protection and Encryption

    Encryption protects data at rest and in transit. Follow these practices:

    • HTTPS everywhere. Obtain TLS certificates from Let’s Encrypt or a trusted CA and enforce HTTPSRedirect middleware.
    • Store sensitive fields (e.g., credit card numbers) encrypted with a library like cryptography using AES‑256‑GCM.
    • Rotate encryption keys regularly and keep them out of source control.
    • Use database‑level encryption for columns that hold personal data, especially when compliance is required.

    Secure Session Management

    Sessions can be a gateway for attackers if mishandled.

    1. Set session.cookie_secure = True and session.cookie_httponly = True to block JavaScript access and force HTTPS.
    2. Implement short session lifetimes and idle timeouts; renew tokens after critical actions.
    3. Store session data server‑side (e.g., Redis) rather than client‑side, unless you use signed, encrypted JWTs.

    Cross‑Site Scripting (XSS) and Content Security Policy (CSP)

    Even with auto‑escaping, user‑generated HTML can slip through.

    • Apply a strict Content Security Policy header to restrict script sources:
    Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none';
    • Sanitize rich‑text inputs with bleach or DOMPurify (via a Python wrapper).
    • Never use mark_safe in Django unless the content is absolutely trusted.

    Logging, Monitoring, and Incident Response

    Visibility is a cornerstone of security.

    1. Log security‑relevant events (failed logins, permission changes, admin actions) using structured JSON logs.
    2. Mask or hash sensitive data before writing to logs.
    3. Integrate with monitoring tools such as Prometheus, ELK Stack, or cloud‑native services (AWS CloudWatch, GCP Cloud Logging).
    4. Set up alerts for anomalous patterns like repeated 401 responses or unusual API usage.
    5. Maintain an incident response playbook: detection → containment → eradication → recovery → post‑mortem.

    Dependency Management and Patch Management

    Third‑party packages are a common attack surface.

    • Pin exact versions in requirements.txt and run pip install -r requirements.txt --require-hashes for reproducible builds.
    • Regularly scan dependencies with tools like bandit, safety, or GitHub Dependabot.
    • Automate security updates in CI/CD pipelines; reject builds that contain known CVEs.
    • Prefer well‑maintained libraries with active security response teams.

    Secure Deployment and Configuration

    Even perfectly written code can be compromised by a sloppy environment.

    1. Run applications behind a reverse proxy (Nginx, Traefik) that terminates TLS and adds security headers.
    2. Use container security best practices: minimal base images, non‑root users, and read‑only file systems.
    3. Separate environments (development, staging, production) and never use debug mode in production (DEBUG=False).
    4. Store secrets in a vault (AWS Secrets Manager, HashiCorp Vault) and inject them at runtime.
    5. Apply OS‑level hardening: disable unnecessary services, enforce firewall rules, and keep the host OS patched.

    Testing and Auditing

    Security is an ongoing process, not a one‑time checklist.

    • Write unit tests that cover authentication, authorization, and input validation edge cases.
    • Run static analysis with bandit or pylint for common security patterns.
    • Perform dynamic testing using tools like OWASP ZAP or Burp Suite against a staging environment.
    • Schedule regular penetration testing, especially before major releases.

    Conclusion

    Securing a Python web application requires a layered approach: clean code, hardened frameworks, encrypted data, vigilant monitoring, and disciplined deployment. By embedding these best practices into your development lifecycle, you reduce risk, build trust with users, and stay ahead of evolving threats. Remember, security is not a destination but a continuous journey—keep learning, keep testing, and keep your stack up to date.

  • Python Multi-Factor Authentication Mfa Setup

    In today’s threat‑rich digital landscape, relying on a single password is no longer enough to protect your applications. Python multi-factor authentication (MFA) setup provides an extra layer of security that combines something you know (a password) with something you have (a token, a mobile app, or a biometric). This guide walks you through the concepts, best practices, and step‑by‑step code snippets you need to implement robust MFA in your Python projects, whether you’re building a Flask API, a Django web app, or a simple command‑line tool.

    Why MFA Matters for Python Applications

    Multi‑factor authentication dramatically reduces the risk of credential‑stuffing attacks, phishing, and data breaches. By demanding a second verification factor, you make it exponentially harder for attackers to gain unauthorized access. For Python developers, integrating MFA also aligns with compliance standards such as GDPR, HIPAA, and PCI DSS, which increasingly require strong authentication mechanisms.

    Core Concepts of Multi‑Factor Authentication

    1. Types of Authentication Factors

    • Knowledge factor: Passwords, PINs, or security questions.
    • Possession factor: One‑time passwords (OTP) generated by authenticator apps, SMS codes, hardware tokens, or push notifications.
    • Inherence factor: Biometrics like fingerprint, facial recognition, or voice.

    2. OTP Generation Methods

    Two popular standards for generating OTPs are:

    • TOTP (Time‑Based OTP): Uses a shared secret and the current time to produce a 6‑digit code that expires after 30 seconds. Implemented via the pyotp library.
    • HOTP (HMAC‑Based OTP): Relies on a counter that increments each time an OTP is generated. Useful for hardware tokens.

    3. Delivery Channels

    Choosing the right delivery channel impacts usability and security:

    • Authenticator apps (Google Authenticator, Authy, Microsoft Authenticator)
    • SMS or voice calls (convenient but vulnerable to SIM swapping)
    • Email (acceptable for low‑risk scenarios)
    • Push notifications (real‑time approval via mobile app)

    Preparing Your Python Environment

    Before diving into code, ensure you have the following tools installed:

    pip install pyotp flask django python-dotenv cryptography

    These packages provide OTP generation (pyotp), web frameworks (flask, django), environment variable handling (python-dotenv), and encryption utilities (cryptography).

    Step‑by‑Step MFA Setup in a Flask Application

    Step 1: Configure Environment Variables

    Store secret keys outside your codebase to prevent leaks. Create a .env file:

    # .env
    FLASK_SECRET_KEY=super_secret_key_123
    MFA_ISSUER_NAME=MyPythonApp
    MFA_ENCRYPTION_KEY=32byteslongbase64encodedkey==

    Step 2: Initialize Flask and Load Secrets

    from flask import Flask, request, session, redirect, url_for, render_template_string
    from dotenv import load_dotenv
    import os, pyotp, base64, hashlib, hmac
    
    load_dotenv()
    app = Flask(__name__)
    app.secret_key = os.getenv('FLASK_SECRET_KEY')
    ISSUER = os.getenv('MFA_ISSUER_NAME')
    ENCRYPTION_KEY = base64.b64decode(os.getenv('MFA_ENCRYPTION_KEY'))

    Step 3: Generate a User‑Specific TOTP Secret

    When a user registers or enables MFA, create a unique secret and store it encrypted in your database.

    def encrypt_secret(secret: str) -> str:
        # Simple HMAC‑based encryption for demonstration (use Fernet in production)
        digest = hmac.new(ENCRYPTION_KEY, secret.encode(), hashlib.sha256).digest()
        return base64.urlsafe_b64encode(digest).decode()
    
    def generate_totp_secret() -> str:
        return pyotp.random_base32()

    Step 4: Show the QR Code to the User

    Most authenticator apps accept a QR code that encodes a otpauth:// URI.

    import qrcode
    import io
    
    def get_qr_code_uri(username: str, secret: str) -> str:
        uri = pyotp.totp.TOTP(secret).provisioning_uri(name=username, issuer_name=ISSUER)
        return uri
    
    def qr_image_bytes(uri: str) -> bytes:
        img = qrcode.make(uri)
        buf = io.BytesIO()
        img.save(buf, format='PNG')
        return buf.getvalue()

    Step 5: Verify the OTP During Login

    def verify_otp(secret: str, token: str) -> bool:
        totp = pyotp.TOTP(secret)
        return totp.verify(token, valid_window=1)  # Allows previous/next interval

    Step 6: Assemble the Flask Routes

    @app.route('/register', methods=['GET', 'POST'])
    def register():
        if request.method == 'POST':
            username = request.form['username']
            # In a real app, save user record first
            secret = generate_totp_secret()
            encrypted = encrypt_secret(secret)
            # Save encrypted secret to DB (omitted)
            session['temp_secret'] = secret  # Store plain secret temporarily for QR generation
            return redirect(url_for('setup_mfa', username=username))
        return '''
            
    Username:
    ''' @app.route('/setup-mfa') def setup_mfa(): username = request.args.get('username') secret = session.get('temp_secret') if not secret: return redirect(url_for('register')) uri = get_qr_code_uri(username, secret) img_bytes = qr_image_bytes(uri) img_base64 = base64.b64encode(img_bytes).decode() return f'''

    Scan this QR code with your authenticator app

    MFA QR

    ''' @app.route('/verify-mfa', methods=['POST']) def verify_mfa(): token = request.form['token'] secret = session.get('temp_secret') if verify_otp(secret, token): # Persist encrypted secret to user record here session.pop('temp_secret', None) return 'MFA enabled successfully!' return 'Invalid code, try again.', 401 @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] # Authenticate password (omitted) # Retrieve encrypted secret from DB, decrypt it secret = retrieve_decrypted_secret(username) # placeholder session['mfa_user'] = username session['mfa_secret'] = secret return redirect(url_for('login_mfa')) return '''
    Username:
    Password:
    ''' @app.route('/login-mfa', methods=['GET', 'POST']) def login_mfa(): if request.method == 'POST': token = request.form['token'] secret = session.get('mfa_secret') if verify_otp(secret, token): session.pop('mfa_secret', None) return f'Welcome, {session["mfa_user"]}!' return 'Invalid MFA code.', 401 return '''
    MFA Code:
    ''' if __name__ == '__main__': app.run(debug=True)

    Implementing MFA in Django: A Quick Overview

    Django developers can leverage the same pyotp library, but Django’s built‑in authentication system simplifies user management.

    • Create a OneTimePassword model that stores the encrypted TOTP secret linked to settings.AUTH_USER_MODEL.
    • Use Django signals (post_save) to generate a secret when a user enables MFA.
    • Render the QR code in a template using the qrcode package and data:image/png;base64 URLs.
    • Add a custom authentication backend that first validates the password, then prompts for the OTP.

    For a full‑featured solution, consider third‑party packages such as django-otp or django-two-factor-auth, which already handle backup tokens, trusted browsers, and recovery codes.

    Best Practices for Secure MFA Implementation

    1. Never store plain‑text secrets. Encrypt TOTP secrets using a strong symmetric cipher (e.g., Fernet) and rotate keys periodically.
    2. Limit OTP verification attempts. Block the account after 5–10 failed attempts to mitigate brute‑force attacks.
  • Python Password Reset Via Email Tutorial

    Forgotten passwords are a common pain point for users, and a seamless password‑reset flow can dramatically improve the experience on any web application. In this tutorial you’ll learn how to implement a robust “Python password reset via email” feature from scratch, using only standard libraries and a lightweight Flask framework. We’ll cover everything from generating secure tokens and configuring an SMTP server to sending reset links and validating them safely. By the end, you’ll have a production‑ready password‑reset system that boosts security, reduces support tickets, and keeps your users happy.

    Why a Proper Email‑Based Reset Is Essential

    When users forget their credentials, a poorly designed reset process can expose your site to account takeover, phishing, or brute‑force attacks. An effective solution must:

    • Verify the user’s identity via a unique, time‑limited token.
    • Send the token through a trusted email channel.
    • Store the token securely and invalidate it after use.
    • Protect against enumeration attacks by providing generic responses.

    Following these best practices ensures that the “Python password reset via email” flow is both user‑friendly and secure.

    Prerequisites

    • Python 3.8+ installed on your development machine.
    • Basic knowledge of Flask (or any micro‑framework) and HTML forms.
    • An SMTP service (Gmail, SendGrid, Mailgun, etc.) with credentials.
    • A SQLite or any relational database to store users and reset tokens.

    Setting Up the Project Structure

    myapp/
    ├─ app.py
    ├─ models.py
    ├─ utils.py
    ├─ templates/
    │  ├─ reset_request.html
    │  └─ reset_password.html
    └─ requirements.txt
    

    This layout keeps the core logic, database models, and utility functions separate, making the code easier to maintain and extend.

    Step 1: Configuring the SMTP Server

    First, install the required package and add your mail settings to app.py:

    pip install Flask Flask-Mail itsdangerous
    
    from flask import Flask
    from flask_mail import Mail, Message
    
    app = Flask(__name__)
    
    # ==== SMTP SETTINGS ====
    app.config['MAIL_SERVER'] = 'smtp.gmail.com'
    app.config['MAIL_PORT'] = 587
    app.config['MAIL_USE_TLS'] = True
    app.config['MAIL_USERNAME'] = 'your_email@gmail.com'
    app.config['MAIL_PASSWORD'] = 'your_app_password'  # use App Passwords for Gmail
    mail = Mail(app)
    

    Replace the placeholders with your actual credentials. For production, store these values in environment variables and load them with python-dotenv to avoid hard‑coding secrets.

    Step 2: Generating a Secure Reset Token

    We’ll use itsdangerous.URLSafeTimedSerializer to create a signed token that expires after a configurable period (default 1 hour).

    # 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='password-reset-salt')
    
    def verify_reset_token(token, expiration=3600):
        serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY'])
        try:
            email = serializer.loads(
                token,
                salt='password-reset-salt',
                max_age=expiration
            )
        except Exception:
            return None
        return email
    

    Make sure app.config['SECRET_KEY'] is a long, random string. The token contains only the user’s email, but it is cryptographically signed, so it cannot be forged.

    Step 3: Creating the Password‑Reset Request View

    This endpoint displays a form where users enter their email address. If the address exists, we send a reset link; otherwise, we return the same generic message to prevent user enumeration.

    # app.py (continued)
    from flask import render_template, request, flash, redirect, url_for
    from utils import generate_reset_token
    from models import User  # assume a simple ORM model with .query.filter_by
    
    @app.route('/reset-password', methods=['GET', 'POST'])
    def reset_request():
        if request.method == 'POST':
            email = request.form.get('email')
            user = User.query.filter_by(email=email).first()
            if user:
                token = generate_reset_token(user.email)
                send_reset_email(user.email, token)
            # Always flash the same message
            flash('If an account with that email exists, a reset link has been sent.', 'info')
            return redirect(url_for('login'))
        return render_template('reset_request.html')
    

    Sending the Reset Email

    # utils.py (continued)
    def send_reset_email(to_email, token):
        reset_url = url_for('reset_token', token=token, _external=True)
        subject = "Your Password Reset Link"
        html_body = f"""
        

    Hello,

    Click the link below to reset your password. This link will expire in 1 hour.

    Reset My Password

    If you didn’t request this, you can safely ignore this email.

    """ msg = Message(subject, recipients=[to_email], html=html_body, sender=app.config['MAIL_USERNAME']) mail.send(msg)

    The _external=True flag generates an absolute URL, which is required for email links.

    Step 4: Building the Reset‑Password Form

    The link in the email points to a route that validates the token and presents a new password form.

    # app.py (continued)
    from utils import verify_reset_token
    
    @app.route('/reset-password/', 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':
            password = request.form.get('password')
            confirm = request.form.get('confirm')
            if password != confirm:
                flash('Passwords do not match.', 'warning')
                return redirect(request.url)
    
            user = User.query.filter_by(email=email).first_or_404()
            user.set_password(password)   # assume a method that hashes the password
            db.session.commit()
            flash('Your password has been updated! You can now log in.', 'success')
            return redirect(url_for('login'))
    
        return render_template('reset_password.html', token=token)
    

    HTML Templates (Simplified)

    Below are minimal examples; feel free to style them with Bootstrap or Tailwind.

    
    <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>
        <label for="confirm">Confirm password:</label>
        <input type="password" name="confirm" id="confirm" required>
        <button type="submit">Update Password</button>
    </form>
    

    Step 5: Securing the Workflow

    Even a functional reset flow can be vulnerable if not hardened. Implement the following safeguards:

    • Rate limiting: Use Flask‑Limiter or a reverse proxy to restrict the number of reset requests per IP address.
    • Token reuse protection: Store a hash of the token in the database and mark it as used after a successful password change.
    • HTTPS everywhere: Ensure both the reset request page and the reset link are served over TLS.
    • Strong password policy: Enforce minimum length, complexity, and check against breached‑password lists.
    • Audit logging: Record reset attempts, successes, and failures for forensic analysis.

    Common Pitfalls and How to Avoid Them

    1. Sending Plain‑Text Passwords

    Never include the new password in the email. Always let the user choose it after clicking the secure link.

    2. Using Predictable Tokens

    Do not roll your own random string. Libraries like itsdangerous or jwt provide cryptographically signed tokens that are far more secure.

    3. Forgetting to Expire Tokens

    Tokens that never expire become a goldmine for attackers. Set a reasonable max_age (e.g., 3600 seconds) and enforce it on verification.

    4. Hard‑Coding Secrets

    Never commit SECRET_KEY, SMTP passwords, or API keys to version control. Use environment variables or secret managers (AWS Secrets Manager, HashiCorp Vault).

    Testing the Complete Flow

    1. Run the Flask app locally: flask run
  • Python Github Oauth Authentication Flow

    Python GitHub OAuth authentication flow is the modern way to let users log in to your web app using their GitHub credentials, while keeping passwords safely out of your hands. In this guide we’ll walk through the theory behind OAuth 2.0, the exact steps to set up a GitHub‑based login in Python, and best‑practice tips that keep your integration secure and SEO‑friendly. Whether you’re building a Flask micro‑service or a full‑blown Django portal, the patterns described here will work out of the box.

    Understanding OAuth 2.0 and GitHub’s Role

    What is OAuth 2.0?

    OAuth 2.0 is an open‑standard authorization framework that enables third‑party applications to obtain limited access to an HTTP service—such as GitHub—on behalf of a resource owner. The flow typically involves three parties:

    • Client – your Python web app.
    • Authorization Server – GitHub’s OAuth endpoint.
    • Resource Server – the GitHub API that serves user data.

    The client never sees the user’s password. Instead, it receives a short‑lived access_token that can be used to call protected endpoints.

    Why Choose GitHub for Authentication?

    GitHub is a trusted identity provider for developers. By leveraging GitHub OAuth, you gain:

    • Instant credibility—users recognize the familiar GitHub login screen.
    • Rich profile data (username, email, public repos) without building a custom user database.
    • Fine‑grained permission scopes (e.g., read:user, repo) that let you request only what you need.

    Prerequisites for a Python GitHub OAuth Flow

    • A GitHub account and access to GitHub Developer Settings.
    • Python 3.8+ installed locally.
    • One of the following web frameworks: Flask (lightweight) or Django (full‑stack).
    • Basic knowledge of HTTP, redirects, and JSON handling.

    Step‑by‑Step Implementation with Flask

    1. Register Your Application on GitHub

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

    • Application name – e.g., “MyPythonApp”.
    • Homepage URL – the public URL of your app.
    • Authorization callback URL – e.g., http://localhost:5000/callback for local testing.

    After saving, GitHub provides a Client ID and Client Secret. Keep the secret out of source control!

    2. Install Required Packages

    pip install Flask requests

    3. Create the Flask App and Configuration

    from flask import Flask, redirect, request, session, url_for, jsonify
    import requests
    import os
    
    app = Flask(__name__)
    app.secret_key = os.urandom(24)  # Secure session cookies
    
    # Load credentials from environment variables
    CLIENT_ID = os.getenv('GITHUB_CLIENT_ID')
    CLIENT_SECRET = os.getenv('GITHUB_CLIENT_SECRET')
    AUTH_BASE_URL = 'https://github.com/login/oauth/authorize'
    TOKEN_URL = 'https://github.com/login/oauth/access_token'
    API_USER_URL = 'https://api.github.com/user'

    4. Build the Authorization URL

    When a user clicks “Login with GitHub”, redirect them to GitHub’s consent page.

    @app.route('/login')
    def login():
        params = {
            'client_id': CLIENT_ID,
            'redirect_uri': url_for('callback', _external=True),
            'scope': 'read:user user:email',
            'state': os.urandom(8).hex()  # CSRF protection
        }
        session['oauth_state'] = params['state']
        auth_url = f"{AUTH_BASE_URL}?{requests.compat.urlencode(params)}"
        return redirect(auth_url)

    5. Handle the Callback and Exchange Code for Token

    GitHub redirects back with code and state. Verify the state, then request an access token.

    @app.route('/callback')
    def callback():
        # Verify state to prevent CSRF attacks
        if request.args.get('state') != session.get('oauth_state'):
            return 'Invalid state parameter', 400
    
        code = request.args.get('code')
        token_response = requests.post(
            TOKEN_URL,
            headers={'Accept': 'application/json'},
            data={
                'client_id': CLIENT_ID,
                'client_secret': CLIENT_SECRET,
                'code': code,
                'redirect_uri': url_for('callback', _external=True),
                'state': session['oauth_state']
            }
        )
        token_json = token_response.json()
        access_token = token_json.get('access_token')
        if not access_token:
            return 'Failed to obtain access token', 400
    
        session['github_token'] = access_token
        return redirect(url_for('profile'))

    6. Access the GitHub API with the Token

    Now you can fetch the authenticated user’s profile.

    @app.route('/profile')
    def profile():
        token = session.get('github_token')
        if not token:
            return redirect(url_for('login'))
    
        user_resp = requests.get(
            API_USER_URL,
            headers={'Authorization': f'token {token}',
                     'Accept': 'application/vnd.github.v3+json'}
        )
        user_data = user_resp.json()
        return jsonify({
            'login': user_data.get('login'),
            'name': user_data.get('name'),
            'avatar_url': user_data.get('avatar_url'),
            'public_repos': user_data.get('public_repos')
        })

    Alternative: Using Django with social-auth-app-django

    If you prefer Django, the social-auth-app-django package abstracts most of the flow. After installing:

    pip install social-auth-app-django

    add the following to settings.py:

    AUTHENTICATION_BACKENDS = (
        'social_core.backends.github.GithubOAuth2',
        'django.contrib.auth.backends.ModelBackend',
    )
    
    SOCIAL_AUTH_GITHUB_KEY = os.getenv('GITHUB_CLIENT_ID')
    SOCIAL_AUTH_GITHUB_SECRET = os.getenv('GITHUB_CLIENT_SECRET')
    SOCIAL_AUTH_GITHUB_SCOPE = ['read:user', 'user:email']

    Include the URLs:

    urlpatterns = [
        path('auth/', include('social_django.urls', namespace='social')),
        # … other routes …
    ]

    Then a simple template link <a href="{% url 'social:begin' 'github' %}">Login with GitHub</a> launches the same OAuth flow without writing any request‑handling code yourself.

    Common Pitfalls and How to Debug Them

    • Mismatched redirect URI – GitHub will reject the request if the redirect_uri does not exactly match the one registered.
    • Missing state verification – Skipping CSRF protection can expose your app to token‑theft attacks.
    • Using the wrong token endpoint – Always POST to https://github.com/login/oauth/access_token with an Accept: application/json header.
    • Expired or revoked tokens – Implement graceful handling (e.g., redirect to /login when a 401 is returned
  • Python Google Oauth2 Login Integration

    Integrating Google OAuth2 login into a Python web application not only provides a seamless sign‑in experience for users, but also boosts your site’s credibility and SEO by leveraging a trusted authentication provider. 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 launch a secure “Sign in with Google” button in minutes.

    Why Choose Google OAuth2 for Python Apps?

    • Universal access: Over a billion Google accounts mean users rarely need to create a new password.
    • Built‑in security: Google handles password storage, multi‑factor authentication, and token revocation.
    • SEO advantage: Faster sign‑in reduces bounce rates, which search engines interpret as a quality signal.
    • Scalable: OAuth2 works the same for small Flask projects and large Django deployments.

    Prerequisites

    • Python 3.8+ installed on your development machine.
    • A Google account to access the Cloud Console.
    • Basic familiarity with Flask or Django (the examples use Flask for brevity).
    • Virtual environment tool (venv, pipenv, or poetry) to keep dependencies isolated.

    Step 1 – Create OAuth2 Credentials in Google Cloud Console

    1. Navigate to Google Cloud Console → APIs & Services → Credentials.
    2. Click Create Credentials → OAuth client ID.
    3. Select Web application as the application type.
    4. Enter a name (e.g., MyPythonApp).
    5. Under Authorized JavaScript origins, add your development URL (e.g., http://localhost:5000).
    6. Under Authorized redirect URIs, add the callback endpoint that will receive the authorization code, such as http://localhost:5000/auth/callback.
    7. Save. Google will display a Client ID and Client Secret**—store them securely (e.g., in a .env file).

    Step 2 – Install Required Python Packages

    python -m venv venv
    source venv/bin/activate  # Windows: venv\Scripts\activate
    pip install Flask requests-oauthlib python-dotenv
    

    Flask provides the web framework, requests‑oauthlib handles the OAuth2 flow, and python‑dotenv loads environment variables securely.

    Step 3 – Configure Environment Variables

    Create a .env file in the project root:

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

    Step 4 – Implement the OAuth2 Flow with Flask

    4.1 Initialize Flask and OAuth Session

    from flask import Flask, redirect, url_for, session, request, jsonify
    from requests_oauthlib import OAuth2Session
    from urllib.parse import urlparse, urljoin
    import os
    from dotenv import load_dotenv
    
    load_dotenv()
    
    app = Flask(__name__)
    app.secret_key = os.getenv('SECRET_KEY')
    
    # Google OAuth2 endpoints
    AUTHORIZATION_BASE_URL = 'https://accounts.google.com/o/oauth2/v2/auth'
    TOKEN_URL = 'https://oauth2.googleapis.com/token'
    USER_INFO_URL = 'https://www.googleapis.com/oauth2/v3/userinfo'
    
    # Scopes we need – email and profile are typical
    SCOPE = ['openid', 'https://www.googleapis.com/auth/userinfo.email',
             'https://www.googleapis.com/auth/userinfo.profile']
    

    4.2 Helper to Verify Safe Redirects

    def is_safe_url(target):
        host_url = request.host_url
        ref_url = urlparse(host_url)
        test_url = urlparse(urljoin(host_url, target))
        return test_url.scheme in ('http', 'https') and ref_url.netloc == test_url.netloc
    

    4.3 Login Route – Redirect to Google

    @app.route('/login')
    def login():
        google = OAuth2Session(
            client_id=os.getenv('GOOGLE_CLIENT_ID'),
            scope=SCOPE,
            redirect_uri=url_for('callback', _external=True)
        )
        authorization_url, state = google.authorization_url(
            AUTHORIZATION_BASE_URL,
            access_type='offline',        # Request refresh token
            prompt='consent'              # Force consent screen for fresh refresh token
        )
        # Store state in session to protect against CSRF
        session['oauth_state'] = state
        return redirect(authorization_url)
    

    4.4 Callback Route – Exchange Code for Tokens

    @app.route('/auth/callback')
    def callback():
        # Verify state to mitigate CSRF attacks
        if request.args.get('state') != session.get('oauth_state'):
            return 'State mismatch', 400
    
        google = OAuth2Session(
            client_id=os.getenv('GOOGLE_CLIENT_ID'),
            redirect_uri=url_for('callback', _external=True),
            state=session['oauth_state']
        )
        token = google.fetch_token(
            TOKEN_URL,
            client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
            authorization_response=request.url
        )
        # Save token (including refresh_token) securely – here we use session for demo
        session['google_token'] = token
    
        # Retrieve user profile
        resp = google.get(USER_INFO_URL)
        user_info = resp.json()
        session['user'] = {
            'id': user_info['sub'],
            'email': user_info['email'],
            'name': user_info.get('name')
        }
        # Redirect to a protected page
        next_url = request.args.get('next') or url_for('profile')
        return redirect(next_url) if is_safe_url(next_url) else redirect(url_for('profile'))
    

    4.5 Protected Profile Page

    @app.route('/profile')
    def profile():
        if 'user' not in session:
            return redirect(url_for('login', next=request.path))
        user = session['user']
        return f"""
        

    Welcome, {user['name']}

    Email: {user['email']}

    Google ID: {user['id']}

    Logout """

    4.6 Logout Route

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

    Step 5 – Managing Refresh Tokens

    Google issues a refresh_token only the first time a user consents, unless you force the consent screen (as shown with prompt='consent'). Store the refresh token in a persistent store (database, encrypted vault) rather than the user session. When the access token expires, use the refresh token to obtain a new one:

    def refresh_google_token(refresh_token):
        extra = {
            'client_id': os.getenv('GOOGLE_CLIENT_ID'),
            'client_secret': os.getenv('GOOGLE_CLIENT_SECRET'),
        }
        oauth = OAuth2Session(client_id=os.getenv('GOOGLE_CLIENT_ID'))
        new_token = oauth.refresh_token(
            TOKEN_URL,
            refresh_token=refresh_token,
            **extra
        )
        return new_token
    

    Step 6 – Common Pitfalls & How to Avoid Them

    • State mismatch errors: Always verify the state parameter returned by Google against the value stored in the session.
    • Redirect URI mismatch: The URI you register in the Cloud Console must exactly match the redirect_uri used in code (including trailing slashes).
    • Missing scopes: If you need additional Google APIs (e.g., Drive), add the corresponding scopes to the SCOPE list.
    • Refresh token loss: Request access_type='offline' and prompt='consent' during the first login, then persist the refresh token.
    • Insecure storage of secrets: Never commit .env files to version control; use environment variables on production servers.

    Step 7 – Security Best Practices

    1. Use HTTPS in production. OAuth2 tokens are bearer tokens; transmitting them over HTTP exposes them to interception.
    2. Validate ID tokens. Google returns an id_token (JWT). Verify its signature and claims (issuer, audience, expiration) using the google-auth library for added security.
    3. Implement token revocation. Provide a logout flow that calls https://oauth2.googleapis.com/revoke?token={token} to invalidate the token on Google’s side.
    4. Set short-lived access tokens. Rely on refresh tokens for long‑term sessions, reducing the window for token abuse.
    5. Apply SameSite cookie attribute. In Flask, set SESSION_COOKIE_SAMESITE = 'Lax' or 'Strict' to mitigate CSRF.

    Step 8 – Testing the Integration

    Before deploying, run the Flask app locally and verify each step:

    export FLASK_APP=app.py
    flask run
    

    Visit http://localhost: