Author: arun

  • Python Beautifulsoup Web Scraping Beginner Guide

    Welcome to the ultimate Python BeautifulSoup web scraping beginner guide. Whether you’re a data enthusiast, a marketer, or a developer looking to automate information gathering, this article will walk you through everything you need to start extracting data from the web with confidence. We’ll cover the basics of web scraping, set up your Python environment, dive into BeautifulSoup’s core features, and share best practices to keep your projects both effective and ethical.

    What Is Web Scraping and Why Use BeautifulSoup?

    Web scraping is the process of programmatically retrieving and parsing the HTML content of web pages to collect structured data. While there are many tools available, BeautifulSoup stands out for beginners because it offers a simple, Pythonic API that works seamlessly with the requests library. It’s lightweight, well‑documented, and perfect for projects ranging from price monitoring to academic research.

    Installing Python and BeautifulSoup

    Before you can start scraping, you need a working Python environment and a few essential packages. Follow these steps to get set up:

    # 1. Verify Python installation (Python 3.8+ recommended)
    python --version
    
    # 2. Create a virtual environment (optional but recommended)
    python -m venv bs4-env
    source bs4-env/bin/activate   # On Windows use: bs4-env\Scripts\activate
    
    # 3. Install requests and BeautifulSoup
    pip install requests beautifulsoup4
    

    Using a virtual environment isolates your scraping project from other Python packages, making debugging easier and keeping your system clean.

    Understanding the Basics of HTML Parsing

    Every web page is built with HTML tags that define its structure. BeautifulSoup transforms raw HTML into a tree of Python objects, allowing you to navigate, search, and modify elements just like you would with a DOM in JavaScript.

    Key BeautifulSoup concepts

    • Tag objects: Represent individual HTML elements (e.g., <div>, <a>).
    • NavigableString: The text inside a tag.
    • find() and find_all(): Methods to locate one or many tags based on name, attributes, or CSS selectors.
    • select(): Uses CSS selectors for powerful, concise queries.

    Step‑by‑Step Guide to Scrape Your First Page

    Let’s put theory into practice by scraping the latest headlines from a news site (example.com). Replace the URL with any site you have permission to scrape.

    1. Fetch the page with requests

    import requests
    from bs4 import BeautifulSoup
    
    url = "https://example.com/news"
    response = requests.get(url, headers={"User-Agent": "Mozilla/5.0"})
    response.raise_for_status()  # Ensure we got a 200 OK response
    

    2. Parse the HTML with BeautifulSoup

    soup = BeautifulSoup(response.text, "html.parser")
    

    3. Locate the headline elements

    Assume each headline lives inside an <h2 class="headline"> tag.

    headlines = soup.find_all("h2", class_="headline")
    for idx, tag in enumerate(headlines, start=1):
        print(f"{idx}. {tag.get_text(strip=True)}")
    

    4. Save the data to a CSV file

    import csv
    
    with open("headlines.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["Index", "Headline"])
        for idx, tag in enumerate(headlines, start=1):
            writer.writerow([idx, tag.get_text(strip=True)])
    

    That’s it! You now have a reusable script that fetches, parses, and stores data—all in under 30 lines of code.

    Handling Common Challenges

    Even a simple script can hit roadblocks. Below are frequent issues and how to solve them.

    Dynamic Content

    • Many modern sites load data with JavaScript. BeautifulSoup alone cannot execute JavaScript.
    • Solution: Use selenium, playwright, or an API like requests-html that renders pages before parsing.

    Pagination

    • Scraping multiple pages requires looping through page URLs or extracting “next” links.
    • Example pattern:
      while next_page:
          response = requests.get(next_page)
          soup = BeautifulSoup(response.text, "html.parser")
          # Extract data...
          next_page = soup.select_one("a.next")["href"]
      

    Rate Limiting & Blocking

    • Servers may block rapid requests or detect non‑browser user agents.
    • Best practices:
      • Respect robots.txt and site terms.
      • Introduce random delays with time.sleep() or random.uniform().
      • Rotate user‑agents and, if needed, use proxy services.

    Best Practices and Legal Considerations

    Scraping responsibly protects both you and the target website.

    • Check the robots.txt file: It indicates which sections are off‑limits for bots.
    • Read the site’s Terms of Service: Some sites explicitly forbid scraping.
    • Limit request frequency: A polite crawl rate is usually 1 request per second or slower.
    • Handle errors gracefully: Use try/except blocks and log failures rather than crashing.
    • Store data ethically: Avoid collecting personal data without consent and comply with GDPR or other regulations.

    Next Steps and Resources

    Now that you’ve mastered the basics, consider expanding your skill set:

    • Advanced parsing: Learn XPath with lxml or CSS selectors for complex structures.
    • Data pipelines: Combine scraping with pandas for cleaning and analysis.
    • Automation: Schedule recurring scrapes using cron (Linux/macOS) or Task Scheduler (Windows).
    • Community tutorials: Check out the official BeautifulSoup documentation, Real Python’s web‑scraping series, and the “Scrapy” framework for large‑scale projects.

    Conclusion

    With just a few lines of Python, BeautifulSoup empowers beginners to transform chaotic web pages into clean, structured data. By following the steps in this guide—setting up a proper environment, mastering HTML parsing, handling common obstacles, and adhering to ethical standards—you’ll be equipped to tackle a wide range of scraping projects. Keep experimenting, stay mindful of legal boundaries, and soon you’ll move from scraping headlines to building sophisticated data pipelines that drive insights and automation.

  • Python Selenium Web Driver Complete Tutorial

    Welcome to the ultimate Python Selenium WebDriver tutorial—your one‑stop guide for mastering browser automation, web testing, and data scraping with Python. Whether you’re a beginner eager to write your first automated test or an experienced QA engineer looking to sharpen your skills, this comprehensive walkthrough covers everything from installation to advanced techniques, all while keeping SEO best practices in mind. Let’s dive in and turn your browser into a programmable robot!

    Why Choose Selenium with Python?

    Selenium remains the industry‑standard tool for web automation because it’s open‑source, supports all major browsers, and integrates seamlessly with Python’s clean syntax. Here are a few reasons why developers and testers love Selenium WebDriver for Python:

    • Cross‑browser compatibility: Chrome, Firefox, Edge, Safari, and more.
    • Rich ecosystem: Works with pytest, unittest, Behave, and CI/CD pipelines.
    • Scalable: From simple UI checks to complex end‑to‑end test suites.
    • Community support: Thousands of tutorials, plugins, and Stack Overflow answers.

    Getting Started: Installation and Setup

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

    Download the latest Python 3.x from python.org and follow the installer prompts. Make sure to check the “Add Python to PATH” option.

    2. Install Selenium via pip

    pip install selenium

    3. Choose and download a WebDriver binary

    Selenium communicates with browsers through driver executables. Below are the most common drivers:

    After downloading, place the driver executable in a folder that’s part of your system PATH or specify its location directly in your script.

    Creating Your First Selenium Script

    Let’s write 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 (adjust the path if needed)
    driver = webdriver.Chrome()  # or webdriver.Chrome(executable_path='path/to/chromedriver')
    
    # 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:', driver.title)
    
    # 6. Close the browser
    driver.quit()
    

    This script demonstrates the core Selenium workflow: initialize driver → navigate → locate elements → interact → clean up.

    Essential Selenium Concepts

    Locating Elements

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

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

    Choosing the most stable locator (usually ID or CSS_SELECTOR) reduces flaky tests.

    Explicit vs. Implicit Waits

    Web pages load asynchronously, so you need to wait for elements to become interactable.

    • Implicit wait: Applies globally, e.g., driver.implicitly_wait(10).
    • Explicit wait: Targets specific conditions with WebDriverWait.
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    wait = WebDriverWait(driver, 15)
    search_box = wait.until(EC.presence_of_element_located((By.NAME, 'q')))
    

    Handling Frames, Alerts, and Pop‑ups

    Real‑world sites often embed content in <iframe> tags or display JavaScript alerts. Selenium provides methods to switch contexts:

    # Switch to an iframe by its name or index
    driver.switch_to.frame('iframe_name')
    # Perform actions inside the frame
    driver.switch_to.default_content()  # Return to main page
    
    # Accept a JavaScript alert
    alert = driver.switch_to.alert
    alert.accept()
    

    Best Practices for Reliable Automation

    1. Use Page Object Model (POM): Encapsulate page elements and actions in separate classes to improve maintainability.
    2. Keep locators DRY: Store them in a central file or as class attributes.
    3. Prefer explicit waits: Reduces false negatives caused by timing issues.
    4. Run tests headlessly for CI: Add options.add_argument('--headless') to Chrome/Firefox options.
    5. Take screenshots on failure: Helps debug flaky tests.

    Advanced Topics

    Running Tests in Parallel

    Speed up your test suite with pytest-xdist or Selenium Grid.

    # Example with pytest-xdist
    pytest -n 4  # Run tests across 4 CPU cores
    

    Integrating with CI/CD Pipelines

    Most CI platforms (GitHub Actions, GitLab CI, Jenkins) support Selenium. A minimal GitHub Actions workflow:

    name: Selenium 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 selenium pytest
          - name: Run tests
            run: |
              pytest tests/
    

    Scraping Dynamic Content

    When static HTML parsing fails, Selenium can render JavaScript‑heavy pages before extracting data.

    driver.get('https://example.com/dynamic')
    items = driver.find_elements(By.CSS_SELECTOR, '.product-name')
    for item in items:
        print(item.text)
    

    Using Selenium with Headless Browsers

    Running browsers without a UI saves resources. Below is a headless Chrome configuration:

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

    Debugging Common Issues

    • SessionNotCreatedException: Mismatch between Chrome version and ChromeDriver. Update both to compatible releases.
    • ElementNotInteractableException: Element is hidden or overlapped. Use JavaScript click or scroll into view.
    • StaleElementReferenceException: Page refreshed after locating the element. Re‑find the element before interacting.

    Resources for Continued Learning

    • Official Selenium docs: selenium.dev
    • Python Selenium GitHub repo: github.com/SeleniumHQ/selenium
    • Automation testing courses on Udemy, Coursera, and Pluralsight.
    • Community forums: Stack Overflow, Reddit r/selenium, and Selenium Discord.

    Conclusion

    By now you should have a solid foundation in Python Selenium WebDriver—from installing the right tools to writing robust, maintainable automation scripts. Remember, the key to success lies in choosing stable locators, leveraging explicit waits, and structuring your code with the Page Object Model. Keep experimenting with headless execution, parallel testing, and CI integration to scale your automation efforts. With practice, you’ll transform repetitive browser tasks into effortless, repeatable processes and boost your productivity as a developer or QA professional.

  • Python Playwright Web Automation Guide

    Welcome to the ultimate Python Playwright web automation guide! Whether you’re a seasoned QA engineer, a developer looking to streamline repetitive tasks, or a data‑scraping enthusiast, Playwright offers a modern, reliable, and fast way to control browsers from Python. In this guide we’ll walk you through everything you need to get started—installation, core concepts, practical examples, and best‑practice tips that will help you build robust automation scripts in no time.

    Why Choose Playwright Over Other Automation Tools?

    • Cross‑browser support: One API works with Chromium, Firefox, and WebKit.
    • Auto‑wait: Playwright intelligently waits for elements to be ready, reducing flaky tests.
    • Network control: Intercept, modify, or block requests with ease.
    • Headless and headed modes: Perfect for CI pipelines and local debugging.
    • Rich debugging tools: Built‑in trace viewer, screenshots, and video recordings.

    Getting Started: Install Playwright for Python

    First, make sure you have Python 3.7+ installed. Then run the following commands in your terminal:

    pip install playwright
    python -m playwright install
    

    The second command downloads the browser binaries (Chromium, Firefox, WebKit) that Playwright needs to run. You can also install a specific browser if you prefer:

    python -m playwright install chromium
    

    Basic Concepts You Must Know

    Browser, Context, and Page

    Playwright’s architecture is built around three core objects:

    • Browser: Represents the actual browser executable (e.g., Chromium).
    • BrowserContext: An isolated session within a browser—similar to an incognito window. Each context has its own cookies, cache, and storage.
    • Page: A single tab or window inside a context where you interact with the DOM.

    Understanding this hierarchy helps you write efficient scripts that reuse contexts for parallel testing.

    Selectors and Locators

    Playwright supports CSS, XPath, text, and role selectors. The page.locator() API is the recommended way to locate elements because it provides built‑in auto‑waiting:

    # Example: click a button with text "Submit"
    await page.locator("text=Submit").click()
    

    Creating Your First Automation Script

    Below is a simple end‑to‑end script that navigates to example.com, fills a form, and takes a screenshot. Save it as demo.py and run with python demo.py.

    import asyncio
    from playwright.async_api import async_playwright
    
    async def run():
        async with async_playwright() as p:
            # Launch Chromium in headed mode for visual debugging
            browser = await p.chromium.launch(headless=False)
            # Create a new isolated context
            context = await browser.new_context()
            # Open a new page (tab)
            page = await context.new_page()
    
            # Navigate to the target website
            await page.goto("https://example.com")
    
            # Wait for the form to be visible and fill it
            await page.locator("#name").fill("John Doe")
            await page.locator("#email").fill("john@example.com")
            await page.locator("text=Submit").click()
    
            # Wait for a success message and capture a screenshot
            await page.locator("text=Thank you").wait_for()
            await page.screenshot(path="success.png")
    
            # Clean up
            await context.close()
            await browser.close()
    
    asyncio.run(run())
    

    This script demonstrates the typical flow: launch → context → page → actions → teardown. Notice the use of await for asynchronous operations, which keeps the script fast and non‑blocking.

    Advanced Features for Real‑World Automation

    1. Handling Authentication and Sessions

    Playwright can store authentication state in a JSON file, allowing you to bypass login steps in subsequent runs:

    # Save authentication state after logging in once
    await context.storage_state(path="auth.json")
    
    # Reuse the saved state in later scripts
    context = await browser.new_context(storage_state="auth.json")
    

    2. Network Interception and Mocking

    Intercepting network requests is invaluable for testing error handling or speeding up tests by mocking heavy API calls:

    await page.route("**/api/v1/orders", lambda route: route.fulfill(
        status=200,
        content_type="application/json",
        body='{"orders": []}'
    ))
    

    3. Parallel Test Execution

    Playwright’s BrowserContext objects can be created concurrently, enabling true parallelism. Here’s a concise example using asyncio.gather:

    async def run_test(url):
        async with async_playwright() as p:
            browser = await p.chromium.launch()
            context = await browser.new_context()
            page = await context.new_page()
            await page.goto(url)
            await page.screenshot(path=f"{url.split('//')[1]}.png")
            await browser.close()
    
    await asyncio.gather(
        run_test("https://example.com"),
        run_test("https://playwright.dev"),
        run_test("https://python.org")
    )
    

    4. Generating Traces for Debugging

    When a test fails, Playwright can generate a trace file that includes screenshots, network logs, and DOM snapshots. Enable tracing with a few lines of code:

    await context.tracing.start(screenshots=True, snapshots=True)
    # ... run your test steps ...
    await context.tracing.stop(path="trace.zip")
    

    Open the resulting trace.zip in Playwright’s Trace Viewer (playwright show-trace trace.zip) to pinpoint the exact moment of failure.

    Best Practices for Maintaining Playwright Scripts

    • Use explicit waits sparingly: Rely on Playwright’s auto‑wait features instead of time.sleep().
    • Separate test data from code: Store URLs, credentials, and selectors in configuration files (e.g., yaml or json).
    • Leverage Page Object Model (POM): Encapsulate page interactions in reusable classes to improve readability and reduce duplication.
    • Run headless in CI/CD: Configure your pipeline to use headless=True and store artifacts (screenshots, traces) for later analysis.
    • Keep browsers up to date: Regularly run python -m playwright install to fetch the latest stable browser builds.

    Integrating Playwright with Popular Testing Frameworks

    Playwright works seamlessly with pytest, unittest, and behave. Below is a quick pytest example that uses fixtures to manage browser lifecycle:

    import pytest
    from playwright.sync_api import sync_playwright
    
    @pytest.fixture(scope="session")
    def browser():
        with sync_playwright() as p:
            browser = p.chromium.launch(headless=True)
            yield browser
            browser.close()
    
    @pytest.fixture
    def page(browser):
        context = browser.new_context()
        page = context.new_page()
        yield page
        context.close()
    
    def test_homepage_title(page):
        page.goto("https://playwright.dev")
        assert "Playwright" in page.title()
    

    SEO Benefits of a Well‑Written Playwright Guide

    Search engines love comprehensive, keyword‑rich content that answers user intent. By naturally incorporating phrases like “Python Playwright tutorial,” “web automation with Playwright,” and “Playwright Python examples,” this guide improves its chances of ranking for related queries. Additionally, using semantic HTML tags (h2, h3, ul, p) helps crawlers understand the article structure, while code snippets increase dwell time—a positive SEO signal.

    Conclusion

    With its powerful API, cross‑browser capabilities, and built‑in reliability features, Playwright is quickly becoming the go‑to choice for Python web automation. By following this guide—installing the library, mastering core concepts, writing clean scripts, and applying advanced techniques—you’ll be equipped to automate complex workflows, create stable test suites, and even scrape data efficiently. Remember to adopt best practices, keep your browsers updated, and leverage Playwright’s tracing tools for rapid debugging. Happy automating, and may your scripts run fast and flake‑free!

  • Python Server-Sent Events Sse Web App

    Server‑Sent Events (SSE) give web developers a simple, efficient way to push real‑time updates from a Python backend directly to a browser without the overhead of WebSockets. In this guide we’ll explore how to build a robust Python SSE web app, why SSE can be the perfect fit for live dashboards, notifications, and streaming data, and we’ll walk through a complete example using Flask and FastAPI. By the end of this post you’ll have a production‑ready template that you can adapt to any project that needs low‑latency, one‑way server communication.

    What Are Server‑Sent Events?

    Server‑Sent Events are part of the HTML5 EventSource API. Unlike WebSockets, which establish a full‑duplex channel, SSE creates a unidirectional stream from server to client. The browser automatically reconnects if the connection drops, and the data is sent as plain text following a simple line‑based format.

    • Lightweight: No binary framing, just UTF‑8 text.
    • Built‑in reconnection: The client retries automatically with an exponential back‑off.
    • Easy to implement: A single HTTP endpoint that returns text/event-stream.
    • SEO‑friendly: Since the page itself is still served via normal HTTP, search engines can crawl the static content while the dynamic part runs in the background.

    When to Choose SSE Over WebSockets

    Both SSE and WebSockets can deliver real‑time data, but they excel in different scenarios. Use SSE when you need:

    1. Simple, one‑way updates (e.g., live scores, stock tickers, chat notifications).
    2. Broad browser support without polyfills (all modern browsers support EventSource).
    3. Low server resource consumption – SSE works over standard HTTP/1.1 or HTTP/2.
    4. Automatic reconnection and event ID tracking out of the box.

    If you need bidirectional communication, binary data, or sub‑millisecond latency, WebSockets remain the better choice.

    Setting Up the Python Environment

    Required Packages

    For this tutorial we’ll use two popular Python web frameworks. You can pick one based on your existing stack:

    • Flask – lightweight, easy to get started.
    • FastAPI – async‑first, built on Starlette, excellent for high‑concurrency.

    Install the dependencies with pip:

    pip install flask fastapi uvicorn

    Building an SSE Endpoint with Flask

    Basic Flask App

    Below is a minimal Flask app that streams the current server time every second.

    from flask import Flask, Response, stream_with_context
    import time
    
    app = Flask(__name__)
    
    def event_stream():
        """Generator that yields a new SSE message every second."""
        counter = 0
        while True:
            counter += 1
            data = f"data: Server time {time.strftime('%Y-%m-%d %H:%M:%S')} (tick {counter})\n\n"
            yield data
            time.sleep(1)
    
    @app.route('/stream')
    def stream():
        # Set the correct MIME type for SSE
        return Response(stream_with_context(event_stream()),
                        mimetype='text/event-stream')
    
    if __name__ == '__main__':
        app.run(debug=True, threaded=True)
    

    Key points:

    • Use stream_with_context to keep Flask’s request context alive.
    • Yield strings that follow the SSE format: data: <payload>\n\n.
    • Set mimetype='text/event-stream' so the browser knows to treat the response as an event stream.

    Client‑Side JavaScript

    On the front‑end, the EventSource object handles the connection automatically.

    <script>
        const source = new EventSource('/stream');
    
        source.onmessage = function(event) {
            console.log('Received:', event.data);
            const log = document.getElementById('log');
            const entry = document.createElement('div');
            entry.textContent = event.data;
            log.prepend(entry);
        };
    
        source.onerror = function(err) {
            console.error('SSE error:', err);
        };
    </script>
    
    <div id="log"></div>
    

    Building an SSE Endpoint with FastAPI

    Why FastAPI?

    FastAPI leverages Python’s asyncio library, allowing thousands of concurrent connections with minimal overhead. Its built‑in support for StreamingResponse makes SSE implementation straightforward.

    Async SSE Example

    from fastapi import FastAPI
    from fastapi.responses import StreamingResponse
    import asyncio
    import datetime
    
    app = FastAPI()
    
    async def event_generator():
        """Async generator that yields a timestamp every second."""
        counter = 0
        while True:
            counter += 1
            now = datetime.datetime.utcnow().isoformat()
            # SSE format: data: ...\n\n
            yield f"data: {{\"time\": \"{now}\", \"tick\": {counter}}}\n\n"
            await asyncio.sleep(1)
    
    @app.get("/sse")
    async def sse_endpoint():
        return StreamingResponse(event_generator(),
                                 media_type="text/event-stream")
    

    FastAPI automatically runs on an ASGI server (e.g., uvicorn). Start it with:

    uvicorn myapp:app --reload

    Client Code for FastAPI SSE

    The JavaScript remains identical because the browser only cares about the text/event-stream MIME type.

    <script>
        const source = new EventSource('/sse');
    
        source.addEventListener('message', (e) => {
            const data = JSON.parse(e.data);
            console.log('Server time:', data.time, 'Tick:', data.tick);
        });
    </script>
    

    Best Practices for Production‑Ready SSE

    1. Use a Reverse Proxy That Supports Streaming

    • Nginx: Set proxy_buffering off; and proxy_cache off; for the SSE location.
    • Apache: Enable mod_proxy_wstunnel and disable buffering with ProxyPass ... ws:// (even though it’s not WebSocket, the same directives apply).

    2. Keep Connections Alive

    Browsers may close idle connections after 30‑60 seconds. Send a comment line (:) as a heartbeat:

    def event_stream():
        while True:
            yield ": keep‑alive\\n\\n"   # comment line, ignored by client
            # then your actual data...
    

    3. Set Appropriate CORS Headers

    If your front‑end lives on a different domain, add CORS support:

    # Flask example
    from flask_cors import CORS
    CORS(app)
    
    # FastAPI example
    from fastapi.middleware.cors import CORSMiddleware
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],   # Adjust for security
        allow_methods=["GET"],
    )
    

    4. Limit Message Size

    Browsers impose a default limit (~64 KB). If you need larger payloads, split them into multiple events or switch to WebSockets.

    5. Graceful Shutdown

    When the server stops, close all generator loops cleanly to avoid “broken pipe” warnings.

    try:
        while running:
            yield data
    except GeneratorExit:
        # Cleanup logic here
        pass
    

    Real‑World Use Cases for Python SSE

    • Live dashboards: Stream sensor data, KPI metrics, or log tails directly into a web UI.
    • Chat notifications: Push “user is typing” or “new message” alerts without opening a full WebSocket channel.
    • Progress monitoring: Show real‑time job progress for background tasks (e.g., Celery workers).
    • IoT telemetry: Feed lightweight device updates to a monitoring console.

    Testing and Debugging SSE

    Browser DevTools

    Open the Network tab, filter by “event‑source”, and you’ll see the continuous stream. Look for:

    • Correct Content-Type: text/event-stream.
    • Absence of Transfer‑Encoding: chunked errors (some proxies mishandle chunked streams).
    • Heartbeat comments keeping the connection alive.

    Command‑Line Testing

    Use curl to verify the raw stream:

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

    The -N flag disables buffering, letting you see each event as it arrives.

    Scaling SSE with Multiple Workers

    Because each SSE connection holds a thread (Flask) or an async task (FastAPI), you’ll eventually need a process manager:

    • Gunicorn with Gevent: Enables cooperative multitasking for Flask.
    • Uvicorn workers: Use uvicorn myapp:app --workers 4 for FastAPI.

    For truly massive scale, consider a message broker (Redis

  • Python Https Local Development Setup

    Developing web applications locally over HTTPS is no longer a luxury—it’s a necessity. Modern browsers, third‑party APIs, and security‑first frameworks expect encrypted connections even during the early stages of development. In this guide we’ll walk you through a complete Python HTTPS local development setup, covering everything from generating self‑signed certificates to configuring popular frameworks like Flask and Django. By the end, you’ll have a reliable, repeatable workflow that mirrors production security, eliminates “mixed‑content” warnings, and keeps your development experience smooth and professional.

    Why Use HTTPS in Local Development?

    Running your app over HTTP may work, but it introduces several hidden pitfalls:

    • Browser security policies block many features (e.g., Service Workers, geolocation) on insecure origins.
    • OAuth and third‑party APIs often require a secure redirect URI, even for localhost.
    • Consistent testing ensures that SSL‑related bugs are caught early, not after deployment.
    • Compliance with corporate policies that mandate encryption for any network traffic.

    Step 1: Generate a Self‑Signed Certificate

    The first step is to create a certificate that your local server can trust. OpenSSL is the most common tool for this task and is available on macOS, Linux, and Windows (via Git Bash or WSL).

    Command line instructions

    # 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=State/L=City/O=MyCompany/OU=Dev/CN=localhost"
    
    # Self‑sign the certificate (valid for 365 days)
    openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt
    
    # Optional: combine key and cert for convenience
    cat localhost.key localhost.crt > localhost.pem
    

    Place the generated localhost.key and localhost.crt files in a secure folder within your project, e.g., certs/. Remember never to commit these files to version control; add them to .gitignore.

    Step 2: Trust the Certificate on Your Machine

    Browsers will still flag a self‑signed certificate as “untrusted” unless you add it to your OS’s trust store.

    macOS

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

    Windows

    • Run mmc.exe and add the Certificates snap‑in for Computer account.
    • Import localhost.crt into Trusted Root Certification Authorities.

    Linux (Ubuntu/Debian)

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

    After trusting the certificate, restart your browser to clear any cached warnings.

    Step 3: Configure Your Python Framework

    Both Flask and Django provide straightforward ways to serve HTTPS locally. Below are minimal examples for each.

    Flask

    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return "Hello, secure Flask!"
    
    if __name__ == '__main__':
        # Use the combined PEM file or separate key/cert
        context = ('certs/localhost.crt', 'certs/localhost.key')
        app.run(host='127.0.0.1', port=8443, ssl_context=context, debug=True)
    

    Run the script with python app.py and visit https://localhost:8443. The debug=True flag enables auto‑reloading, which works seamlessly over HTTPS.

    Django

    Django doesn’t ship with built‑in HTTPS support for the development server, but you can wrap it with runsslserver or use gunicorn for a quick setup.

    • Option 1: runsslserver
    # Install the package
    pip install django-sslserver
    
    # Add to INSTALLED_APPS in settings.py
    INSTALLED_APPS += ['sslserver']
    
    # Run the server
    python manage.py runsslserver 127.0.0.1:8443 \
        --certificate certs/localhost.crt \
        --key certs/localhost.key
    
    • Option 2: gunicorn
    # Install gunicorn
    pip install gunicorn
    
    # Run with SSL
    gunicorn myproject.wsgi:application \
        --bind 127.0.0.1:8443 \
        --certfile certs/localhost.crt \
        --keyfile certs/localhost.key
    

    Both commands expose your Django app at https://localhost:8443 with a valid TLS handshake.

    Step 4: Automate the Workflow with Scripts

    Manually typing OpenSSL commands and server start‑up flags can be error‑prone. Create a small make or npm script to streamline the process.

    Using a Makefile

    # Makefile
    CERT_DIR=certs
    KEY=$(CERT_DIR)/localhost.key
    CRT=$(CERT_DIR)/localhost.crt
    
    generate:
    \topenssl genrsa -out $(KEY) 2048
    \topenssl req -new -key $(KEY) -out $(CERT_DIR)/localhost.csr -subj "/CN=localhost"
    \topenssl x509 -req -days 365 -in $(CERT_DIR)/localhost.csr -signkey $(KEY) -out $(CRT)
    
    flask:
    \tpython flask_app.py
    
    django:
    \tpython manage.py runsslserver 127.0.0.1:8443 --certificate $(CRT) --key $(KEY)
    
    .PHONY: generate flask django
    

    Now you can run make generate once, then make flask or make django whenever you need a secure local server.

    Step 5: Testing HTTPS Locally

    After your server is up, verify the TLS configuration with these tools:

    • curl: curl -v https://localhost:8443 should show SSL connection using TLS without certificate errors.
    • Browser DevTools: Open the Security tab to confirm the connection is “Secure”.
    • SSL Labs Local Test: Use ssllabs-scan or similar CLI tools to check protocol versions and cipher suites.

    For automated tests, Python’s requests library can be configured to trust your local cert:

    import requests
    
    resp = requests.get('https://localhost:8443', verify='certs/localhost.crt')
    print(resp.text)
    

    Best Practices & Common Pitfalls

    Even though a self‑signed cert is sufficient for development, following best practices will save you time when you transition to production.

    Best Practices

    • Never commit private keys. Use .gitignore and environment variables to reference certificate paths.
    • Rotate certificates regularly. Even local certs should be regenerated every few months to avoid stale keys.
    • Match the hostname. Use localhost or a custom DNS entry (e.g., myapp.local) and update /etc/hosts accordingly.
    • Enable HTTP/2. Modern browsers prefer HTTP/2; tools like hypercorn or uvicorn support it out of the box.

    Common Pitfalls

    • Port conflicts. Port 443 is often reserved; use 8443 or another high‑numbered port for local HTTPS.
    • Browser cache. After trusting a cert, you may still see warnings until you clear the cache or restart the browser.
    • Mixed‑content errors. Ensure all assets (CSS, JS, images) are requested via https:// or protocol‑relative URLs.
    • Incorrect file permissions. Private keys should be readable only by the user running the server (e.g., chmod 600 localhost.key).

    Advanced: Using Docker for Consistent HTTPS Environments

    If your team works with containers, embedding the certificate generation inside a Dockerfile guarantees that every developer gets the same setup.

    # Dockerfile
    FROM python:3.12-slim

    WORKDIR /app
    COPY requirements.txt .
    RUN pip install -r requirements.txt

    # Generate self‑signed cert at build time
    RUN apt-get update && apt-get install -y openssl && \
    mkdir -p /certs && \
    openssl req -x509 -nodes -days 365

  • Python Web Security Best Practices Guide

    In today’s hyper‑connected world, building a Python web application is only half the battle—securing it is the other. Whether you’re using Flask, Django, FastAPI, or any other framework, the same security fundamentals apply. This guide walks you through the most effective Python web security best practices, from input validation to deployment hardening, helping you protect your users and your reputation.

    Why Python Web Security Matters

    Python’s popularity stems from its readability and extensive ecosystem, but attackers often target the very conveniences that make development fast. Vulnerabilities such as injection attacks, cross‑site scripting (XSS), and insecure deserialization can compromise data, steal credentials, or even take over your server. By adopting a security‑first mindset early, you reduce technical debt and avoid costly breaches.

    Secure Coding Foundations

    1. Validate and Sanitize All Input

    • Never trust client data. Use whitelists (allowed characters, formats, ranges) instead of blacklists.
    • Leverage libraries like pydantic (FastAPI) or Django’s built‑in validators to enforce type safety.
    • For raw data, employ re patterns or cerberus schemas to reject malformed input.

    2. Use Parameterized Queries

    SQL injection remains one of the most common attack vectors. Always use parameterized statements or an ORM that abstracts query building.

    # Using psycopg2 with placeholders
    cursor.execute(
        "SELECT * FROM users WHERE email = %s AND is_active = %s",
        (user_email, True)
    )
    

    Or with Django ORM:

    User.objects.filter(email=user_email, is_active=True)
    

    3. Encode Output Properly

    Cross‑site scripting (XSS) exploits arise when untrusted data is rendered in HTML without escaping. Use framework‑provided auto‑escaping:

    • In Django templates, variables are escaped by default.
    • In Jinja2 (Flask/FastAPI), enable autoescape=True or use the |e filter.

    4. Protect Against CSRF

    Cross‑Site Request Forgery (CSRF) tricks authenticated users into performing unwanted actions. Implement CSRF tokens:

    • Django: {% csrf_token %} in forms and CsrfViewMiddleware enabled.
    • Flask: Flask-WTF provides csrf_token automatically.
    • FastAPI: Use fastapi-csrf-protect middleware.

    5. Secure Session Management

    • Store session identifiers in HttpOnly, Secure cookies to prevent JavaScript access and transmission over plain HTTP.
    • Set SameSite=Lax or Strict to mitigate CSRF.
    • Regenerate session IDs after login and logout to avoid fixation attacks.

    Authentication & Authorization

    Strong Password Policies

    • Require minimum length (12+ characters) and complexity.
    • Hash passwords with argon2 or bcrypt, never MD5 or SHA1.
    • Use django.contrib.auth.password_validation or passlib for custom checks.

    Multi‑Factor Authentication (MFA)

    Adding a second factor dramatically reduces credential‑theft risk. Integrate TOTP (Google Authenticator) or WebAuthn using libraries such as django-otp or pyotp.

    Principle of Least Privilege

    • Assign roles with the minimum permissions needed.
    • In Django, use django-guardian for object‑level permissions.
    • For API endpoints, enforce scopes or JWT claims.

    Secure Token Handling

    When using JWTs or API keys:

    • Sign tokens with strong algorithms (HS256 with a secret > 256 bits or RS256 with a private key).
    • Set short expiration times and rotate secrets regularly.
    • Never store secrets in source control—use environment variables or secret managers.

    Data Protection

    Encryption in Transit

    All traffic must be served over HTTPS. Obtain certificates from a trusted CA (Let’s Encrypt is free) and configure strict TLS settings:

    • Disable TLS 1.0/1.1.
    • Prefer modern cipher suites (e.g., AES_256_GCM).
    • Enable HTTP Strict Transport Security (HSTS) with max-age=31536000; includeSubDomains.

    Encryption at Rest

    • Encrypt sensitive database columns using django-encrypted-model-fields or SQLAlchemy’s cryptography integration.
    • Store encryption keys in a vault (AWS KMS, HashiCorp Vault) rather than hard‑coding.

    Secure Logging

    Logs are invaluable for incident response but can leak secrets.

    • Redact passwords, tokens, and PII before writing to logs.
    • Use structured logging (JSON) with structlog for easier parsing.
    • Rotate logs regularly and enforce file permissions (600).

    Framework‑Specific Hardening

    Django Security Checklist

    • SECURE_BROWSER_XSS_FILTER = True
    • SECURE_CONTENT_TYPE_NOSNIFF = True
    • SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE = True
    • X_FRAME_OPTIONS = 'DENY' (or 'SAMEORIGIN')
    • Use django.middleware.security.SecurityMiddleware to enforce many of these automatically.

    Flask Security Enhancements

    • Install Flask-Talisman to set security headers (CSP, HSTS, X‑Content‑Type‑Options).
    • Enable SESSION_COOKIE_HTTPONLY and SESSION_COOKIE_SECURE.
    • Validate request data with marshmallow schemas.

    FastAPI Production Tips

    • Use uvicorn[standard] with --proxy-headers behind a reverse proxy (NGINX) that terminates TLS.
    • Apply starlette.middleware.cors.CORSMiddleware with a whitelist of origins.
    • Leverage pydantic models for strict request validation.

    Testing and Monitoring

    Static Code Analysis

    Integrate tools into CI/CD pipelines:

    • bandit – scans Python code for common security issues.
    • pylint with security plugins.
    • Dependency checkers like safety or pip-audit to detect vulnerable packages.

    Dynamic Testing

    • Run OWASP ZAP or Burp Suite against your staging environment.
    • Use pytest with pytest-django or pytest-flask to create security‑focused test cases (e.g., ensure CSRF tokens are required).

    Runtime Monitoring

    • Enable request‑level logging with unique request IDs.
    • Set up alerts for anomalous patterns (e.g., repeated failed logins) using tools like Sentry or Prometheus + Alertmanager.
    • Consider a Web Application Firewall (WAF) such as ModSecurity in front of your app.

    Deployment Hardening

    Container Security

    • Base images should be minimal (e.g., python:3.12-slim).
    • Run containers as non‑root users.
    • Scan images with trivy or clair before deployment.

    Server Configuration

    • Disable directory listings and unnecessary modules.
    • Limit request size (e.g., client_max_body_size in NGINX) to mitigate DoS.
    • Use a reverse proxy (NGINX, Caddy) to handle TLS termination and rate limiting.

    Continuous Updates

    Regularly patch both your Python runtime and third‑party libraries. Subscribe to security mailing lists (Python‑security‑announce, CVE‑Details) and automate dependency upgrades with tools like Dependabot or Renovate.

    Conclusion

    Securing a Python web application is a continuous process that blends disciplined coding, robust framework configurations, vigilant monitoring, and proactive updates. By embedding these best practices—from input validation and proper authentication to container hardening—you’ll build resilient services that protect user data and maintain trust. Remember, security isn’t a one‑time checklist; it’s an ongoing commitment to staying ahead of emerging threats while delivering reliable, high‑performance Python web experiences.

  • Python Multi-Factor Authentication Mfa Setup

    In today’s security‑first landscape, a single password is no longer enough to protect user accounts. Multi‑factor authentication (MFA) adds an extra layer of defense by requiring users to prove their identity with something they know, something they have, or something they are. If you’re a Python developer looking to bolster the security of your web or API projects, this guide walks you through everything you need to know to set up robust MFA—from the theory behind it to hands‑on code examples using popular libraries and frameworks.

    Why MFA Matters for Python Applications

    Cyber‑criminals constantly evolve their tactics, and credential stuffing attacks have surged by more than 50 % in the past two years. Implementing MFA can:

    • Reduce the risk of unauthorized access by requiring a second verification step.
    • Boost user trust—customers feel safer knowing their data is protected.
    • Help meet compliance standards such as GDPR, HIPAA, and PCI‑DSS, which often mandate MFA for privileged accounts.
    • Improve overall security posture without drastically changing your existing authentication flow.

    Core Concepts Behind Multi‑Factor Authentication

    Types of Factors

    MFA combines at least two of the following:

    • Knowledge factor – something the user knows (password, PIN).
    • Possession factor – something the user has (smartphone, hardware token).
    • Inherence factor – something the user is (fingerprint, facial recognition).

    Common MFA Methods in Python

    When building a Python solution, the most widely adopted methods are:

    1. Time‑Based One‑Time Passwords (TOTP) – generated by apps like Google Authenticator or Authy.
    2. SMS/Email OTP – a code sent to the user’s phone or inbox.
    3. Push notifications – a prompt sent to a mobile app for approval.
    4. Hardware security keys – U2F or WebAuthn devices such as YubiKey.

    Choosing the Right Python Library

    Several mature libraries simplify MFA implementation. Below is a quick comparison to help you decide:

    Library Supported Methods Framework Compatibility Documentation
    pyotp TOTP, HOTP Flask, Django, FastAPI, any Comprehensive, examples
    django-otp TOTP, YubiKey, SMS Django only Well‑maintained
    flask-2fa TOTP, Email OTP Flask only Simple API
    python‑webauthn WebAuthn/U2F Any (requires custom integration) Advanced, security‑focused

    For most projects, pyotp offers the perfect blend of flexibility and simplicity, especially when you need a cross‑framework solution.

    Step‑by‑Step: Implementing TOTP MFA with PyOTP

    1. Install the Required Packages

    pip install pyotp qrcode[pil] Flask

    2. Generate a Secret Key for Each User

    The secret key is the shared secret between the server and the authenticator app. Store it securely (e.g., encrypted column in your database).

    import pyotp
    import os
    
    def generate_secret():
        # 32‑character base32 string – safe for QR code generation
        return pyotp.random_base32()
        
    user_secret = generate_secret()
    # Save user_secret to the user record in DB
    

    3. Create a QR Code for Easy Enrollment

    Most users prefer scanning a QR code rather than typing the secret manually. The following Flask route renders a QR code that can be scanned by Google Authenticator, Authy, or any TOTP app.

    from flask import Flask, render_template_string, request, redirect, url_for
    import qrcode
    import io
    import base64
    
    app = Flask(__name__)
    
    @app.route('/mfa/setup')
    def mfa_setup():
        secret = user_secret  # retrieve from logged‑in user record
        totp_uri = pyotp.totp.TOTP(secret).provisioning_uri(name='user@example.com', issuer_name='MyApp')
        img = qrcode.make(totp_uri)
        buf = io.BytesIO()
        img.save(buf, format='PNG')
        img_b64 = base64.b64encode(buf.getvalue()).decode('utf-8')
        return render_template_string('''
            

    Scan this QR Code with your Authenticator App

    MFA QR Code

    After scanning, enter the 6‑digit code below to verify.

    ''', img_data=img_b64)

    4. Verify the Token Provided by the User

    When the user submits the 6‑digit code, compare it against the server‑generated TOTP value.

    @app.route('/mfa/verify', methods=['POST'])
    def mfa_verify():
        token = request.form['token']
        secret = user_secret  # fetch from DB again
        totp = pyotp.TOTP(secret)
        if totp.verify(token):
            # Mark MFA as enabled for the user
            return 'MFA setup successful!'
        else:
            return 'Invalid code. Please try again.', 400
    

    5. Enforce MFA on Login

    Modify your login flow to check whether the user has MFA enabled. If so, prompt for the TOTP after password verification.

    def login(username, password):
        user = get_user(username)
        if not user or not check_password(user, password):
            return 'Invalid credentials', 401
    
        if user.mfa_enabled:
            # Store user ID in session temporarily and redirect to MFA page
            session['pre_mfa_user_id'] = user.id
            return redirect(url_for('mfa_challenge'))
        else:
            # Regular login without MFA
            session['user_id'] = user.id
            return redirect(url_for('dashboard'))
    
    @app.route('/mfa/challenge', methods=['GET', 'POST'])
    def mfa_challenge():
        if request.method == 'POST':
            token = request.form['token']
            user = get_user_by_id(session['pre_mfa_user_id'])
            if pyotp.TOTP(user.mfa_secret).verify(token):
                session['user_id'] = user.id
                session.pop('pre_mfa_user_id')
                return redirect(url_for('dashboard'))
            else:
                return 'Invalid MFA code', 400
        return render_template_string('''
            

    Enter your MFA code

    ''')

    Beyond TOTP: Adding SMS or Email OTP

    If you need a fallback method for users who don’t have an authenticator app, integrate an SMS or email service. The workflow is similar—generate a random numeric code, send it via the chosen channel, and verify it within a short time window (typically 5‑10 minutes).

    • SMS providers: Twilio, Nexmo, Plivo.
    • Email services: SendGrid, Amazon SES, Mailgun.
    • Store the OTP hash (e.g., SHA‑256) instead of plain text for extra security.

    Sample Code for Email OTP

    import secrets, hashlib, time
    from flask_mail import Mail, Message
    
    mail = Mail(app)
    
    def generate_otp(length=6):
        return ''.join(secrets.choice('0123456789') for _ in range(length))
    
    def send_email_otp(user_email):
        otp = generate_otp()
        # Store a hash with expiration timestamp
        otp_hash = hashlib.sha256(otp.encode()).hexdigest()
        cache.set(f'otp:{user_email}', otp_hash, timeout=300)  # 5 minutes
    
        msg = Message('Your Login OTP', recipients=[user_email])
        msg.body = f'Your one‑time code is {otp}. It expires in 5 minutes.'
        mail.send(msg)
    

    Best Practices for Secure MFA Implementation

    • Never expose the secret key in URLs, logs, or client‑side code.
    • Rate‑limit verification attempts to mitigate brute‑force attacks.
    • Use HTTPS everywhere—MFA tokens are as sensitive as passwords.
    • Provide backup codes for users who lose their device; store them hashed.
    • Allow MFA reset only after strong identity verification (e.g., support ticket with ID verification).
  • Python Password Reset Via Email Tutorial

    Ever struggled to let users regain access to their accounts without compromising security? A reliable password‑reset flow is a must‑have feature for any modern web application, and Python makes it surprisingly straightforward. In this tutorial we’ll walk through every step required to build a secure, email‑based password reset system—from generating a time‑limited token to sending the reset link via SMTP and finally updating the user’s password safely. Whether you’re using Flask, Django, or a lightweight script, the concepts remain the same, and you’ll walk away with production‑ready code you can drop into your next project.

    Why a Proper Password Reset Matters

    Implementing a password reset isn’t just about convenience; it’s a critical security control. A well‑designed flow prevents:

    • Account takeover: Attackers can’t guess or reuse old passwords.
    • Phishing exploits: Tokens are short‑lived and bound to a specific user.
    • Brute‑force attacks: Rate limiting and token expiration stop automated attempts.

    By following best practices—such as using cryptographically strong tokens, HTTPS, and secure hashing—you protect both your users and your brand reputation.

    High‑Level Overview of the Process

    1. Request Reset: User submits their email address.
    2. Generate Token: Server creates a signed, time‑limited token.
    3. Send Email: An email containing a reset URL is dispatched via SMTP.
    4. Validate Token: When the user clicks the link, the token is verified.
    5. Update Password: User enters a new password, which is hashed and stored.

    Setting Up the Environment

    Required Packages

    For this tutorial we’ll use Flask as the web framework, itsdangerous for token handling, and Flask-Mail (or smtplib for a pure‑Python approach). Install them with:

    pip install Flask itsdangerous Flask-Mail python-dotenv

    We also recommend python-dotenv to keep secret keys out of source control.

    Project Structure

    .
    ├── app.py
    ├── config.py
    ├── templates
    │   ├── reset_request.html
    │   ├── reset_password.html
    │   └── email_reset.html
    └── .env
    

    Step‑by‑Step Implementation

    1. Configure Flask and Mail Settings

    # config.py
    import os
    from dotenv import load_dotenv
    
    load_dotenv()  # Loads variables from .env
    
    class Config:
        SECRET_KEY = os.getenv('SECRET_KEY', 'dev-secret-key')
        SECURITY_PASSWORD_SALT = os.getenv('SECURITY_PASSWORD_SALT', 'dev-salt')
        # SMTP configuration
        MAIL_SERVER = os.getenv('MAIL_SERVER', 'smtp.gmail.com')
        MAIL_PORT = int(os.getenv('MAIL_PORT', 587))
        MAIL_USE_TLS = os.getenv('MAIL_USE_TLS', 'true').lower() == 'true'
        MAIL_USERNAME = os.getenv('MAIL_USERNAME')
        MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
        MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')

    2. Initialize Flask, Mail, and Token Serializer

    # app.py
    from flask import Flask, render_template, request, flash, redirect, url_for
    from flask_mail import Mail, Message
    from itsdangerous import URLSafeTimedSerializer, SignatureExpired, BadSignature
    from config import Config
    
    app = Flask(__name__)
    app.config.from_object(Config)
    
    mail = Mail(app)
    serializer = URLSafeTimedSerializer(app.config['SECRET_KEY'])

    3. Create the Reset Request Form

    The user supplies their email address. If the address exists in the database, we generate a token and send the email.

    @app.route('/reset', methods=['GET', 'POST'])
    def reset_request():
        if request.method == 'POST':
            email = request.form['email']
            # TODO: Replace with real DB lookup
            user = get_user_by_email(email)
            if user:
                token = serializer.dumps(email, salt=app.config['SECURITY_PASSWORD_SALT'])
                reset_url = url_for('reset_token', token=token, _external=True)
                send_reset_email(user.email, reset_url)
                flash('A password reset link has been sent to your email.', 'info')
                return redirect(url_for('login'))
            else:
                flash('Email address not found.', 'danger')
        return render_template('reset_request.html')

    4. Sending the Reset Email

    def send_reset_email(to_email, reset_url):
        subject = "Your Password Reset Link"
        html_body = render_template('email_reset.html', reset_url=reset_url)
        msg = Message(subject=subject, recipients=[to_email], html=html_body)
        mail.send(msg)

    5. Build the Email Template

    <!-- templates/email_reset.html -->
    <p>Hello,</p>
    <p>You requested a password reset. Click the link below to set a new password. This link will expire in 30 minutes.</p>
    <p><a href="{{ reset_url }}">Reset My Password</a></p>
    <p>If you didn’t request this, please ignore this email.</p>
    <p>Thanks,<br>Your Application Team</p>
    

    6. Validate the Token and Show the New Password Form

    @app.route('/reset/<token>', methods=['GET', 'POST'])
    def reset_token(token):
        try:
            email = serializer.loads(
                token,
                salt=app.config['SECURITY_PASSWORD_SALT'],
                max_age=1800  # 30 minutes
            )
        except SignatureExpired:
            flash('The reset link has expired.', 'danger')
            return redirect(url_for('reset_request'))
        except BadSignature:
            flash('Invalid reset token.', 'danger')
            return redirect(url_for('reset_request'))
    
        if request.method == 'POST':
            password = request.form['password']
            confirm = request.form['confirm']
            if password != confirm:
                flash('Passwords do not match.', 'danger')
                return render_template('reset_password.html')
            # TODO: Hash password and update DB
            update_user_password(email, password)
            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)

    7. Secure Password Storage

    Never store plain‑text passwords. Use werkzeug.security.generate_password_hash (or bcrypt) to hash the new password before saving.

    from werkzeug.security import generate_password_hash
    
    def update_user_password(email, raw_password):
        hashed = generate_password_hash(raw_password)
        # Replace with actual DB update logic
        user = get_user_by_email(email)
        user.password_hash = hashed
        db.session.commit()

    8. Adding Rate Limiting (Optional but Recommended)

    To stop abuse, integrate Flask-Limiter or implement a simple counter in your database that tracks how many reset requests a user makes within a given timeframe.

    Testing the Flow Locally

    1. Set up a .env file with your SMTP credentials (e.g., Gmail app password).
    2. Run flask run and navigate to /reset.
    3. Enter a registered email address; you should receive a reset link.
    4. Click the link, change the password, and verify you can log in with the new credentials.

    If you’re using Gmail, remember to enable “Less secure app access” or, better yet, create an App Password for added security.

    Deploying to Production

    Key Checklist

    • HTTPS Only: Force SSL/TLS to protect token leakage.
    • Environment Secrets: Store SECRET_KEY, SECURITY_PASSWORD_SALT, and mail credentials in a secrets manager (AWS Secrets Manager, Docker secrets, etc.).
    • Token Expiration: Keep the window short (15‑30 minutes) to limit exposure.
    • Audit Logging: Record reset attempts and successes for compliance.
    • CAPTCHA: Add a CAPTCHA challenge on the reset request form to deter bots.

    Example Production Settings

    # .env (do NOT commit!)
    SECRET_KEY=super‑strong‑random‑bytes‑base64
    SECURITY_PASSWORD_SALT=another‑random‑string
    MAIL_SERVER=smtp.sendgrid.net
    MAIL_PORT=587
    MAIL_USE_TLS=true
    MAIL_USERNAME=apikey
    MAIL_PASSWORD=SG.xxxxxxx  # SendGrid API key
    MAIL_DEFAULT_SENDER=no-reply@yourdomain.com

    Common Pitfalls and How to Avoid Them

    • Token Reuse: Always generate a fresh token per request; never store the token in the database.
    • Plain‑Text Links in Logs: Mask the reset URL when logging to avoid accidental exposure.
    • Weak Password Policies: Enforce minimum length, complexity, and disallow common passwords.
    • Missing CSRF Protection: Use Flask‑WTF or Django’s built‑in CSRF middleware on all forms.
    • Unverified Email Addresses: Ensure
  • Python Github Oauth Authentication Flow

    When you build a Python app that needs to interact with a user’s GitHub account, the most secure and user‑friendly way to do it is through GitHub’s OAuth 2.0 authentication flow. In this guide we’ll walk through every step—from registering your OAuth app on GitHub to exchanging the authorization code for an access token and finally calling the GitHub API—all using clean, production‑ready Python code. Whether you’re using Flask, Django, or a simple script, mastering this flow will make your application feel native, protect user data, and boost your SEO by targeting the keyword‑rich phrase “Python GitHub OAuth authentication flow.”

    Understanding OAuth 2.0 Basics

    What is OAuth 2.0?

    OAuth 2.0 is an open standard for delegated authorization. Instead of asking users for their password, an app redirects them to the service provider (GitHub) where they log in and grant specific permissions. The provider then returns a short‑lived access token that the app can use to act on the user’s behalf.

    Why GitHub Uses OAuth

    • Security: Passwords never leave GitHub’s domain.
    • Granular scopes: You can request only the permissions you truly need (e.g., repo, read:user).
    • Revocable tokens: Users can revoke access at any time without changing their password.

    Prerequisites for Python GitHub OAuth

    1. Python 3.8+ installed on your development machine.
    2. A GitHub account (obviously) and the ability to create an OAuth App in your profile settings.
    3. A web framework – the examples use Flask, but the same concepts apply to Django, FastAPI, or plain http.server.
    4. Familiarity with requests library for making HTTP calls.
    5. Environment variable handling (e.g., python‑dotenv) to keep client secrets out of source control.

    Step‑by‑Step Implementation in Python

    1. Register a GitHub OAuth App

    Go to GitHub Settings → Developer settings → OAuth Apps and click “New OAuth App”. Fill in:

    • Application name – e.g., “My Python Dashboard”.
    • Homepage URL – your local development URL, such as http://localhost:5000.
    • Authorization callback URL – the endpoint that will receive the code, e.g., http://localhost:5000/callback.

    After saving, GitHub will give you a Client ID and a Client Secret**. Store both securely; never commit the secret to Git.

    2. Set Up a Flask Project

    # app.py
    from flask import Flask, redirect, request, session, url_for, jsonify
    import os
    import requests
    from urllib.parse import urlencode
    
    app = Flask(__name__)
    app.secret_key = os.getenv('FLASK_SECRET_KEY', 'dev-secret')  # replace in production
    
    # Load GitHub credentials from environment
    GITHUB_CLIENT_ID = os.getenv('GITHUB_CLIENT_ID')
    GITHUB_CLIENT_SECRET = os.getenv('GITHUB_CLIENT_SECRET')
    

    3. Build the Authorization URL

    The user is sent to GitHub’s authorize endpoint with a few query parameters. The most common are client_id, redirect_uri, scope, and a random state token to prevent CSRF attacks.

    @app.route('/')
    def index():
        state = os.urandom(16).hex()
        session['oauth_state'] = state
        params = {
            'client_id': GITHUB_CLIENT_ID,
            'redirect_uri': url_for('callback', _external=True),
            'scope': 'read:user repo',
            'state': state,
            'allow_signup': 'true'
        }
        auth_url = f"https://github.com/login/oauth/authorize?{urlencode(params)}"
        return f'<a href="{auth_url}">Login with GitHub</a>'
    

    4. Handle the Callback and Exchange Code for a Token

    GitHub redirects the user back to /callback with code and state. Verify the state, then POST to GitHub’s token endpoint.

    @app.route('/callback')
    def callback():
        # Verify state parameter
        received_state = request.args.get('state')
        if received_state != session.get('oauth_state'):
            return 'State mismatch. Potential CSRF attack.', 400
    
        code = request.args.get('code')
        token_url = 'https://github.com/login/oauth/access_token'
        headers = {'Accept': 'application/json'}
        data = {
            'client_id': GITHUB_CLIENT_ID,
            'client_secret': GITHUB_CLIENT_SECRET,
            'code': code,
            'redirect_uri': url_for('callback', _external=True),
            'state': received_state
        }
        token_response = requests.post(token_url, headers=headers, data=data)
        token_json = token_response.json()
        access_token = token_json.get('access_token')
        if not access_token:
            return f"Error retrieving token: {token_json}", 400
    
        session['github_token'] = access_token
        return redirect(url_for('profile'))
    

    5. Access the GitHub API with the Token

    Now you can make authenticated requests on behalf of the user. Below we fetch the user’s public profile and list their repositories.

    @app.route('/profile')
    def profile():
        token = session.get('github_token')
        if not token:
            return redirect(url_for('index'))
    
        api_headers = {'Authorization': f'token {token}'}
        user_resp = requests.get('https://api.github.com/user', headers=api_headers)
        repos_resp = requests.get('https://api.github.com/user/repos', headers=api_headers, params={'per_page': 5})
    
        user_data = user_resp.json()
        repos = repos_resp.json()
    
        return jsonify({
            'login': user_data.get('login'),
            'name': user_data.get('name'),
            'public_repos': user_data.get('public_repos'),
            'sample_repos': [repo['full_name'] for repo in repos]
        })
    

    Common Pitfalls and Debugging Tips

    • Missing or mismatched state value: Always store the generated state in the session and compare it on callback.
    • Wrong redirect URI: The URL registered on GitHub must exactly match the one you send in the request (including trailing slashes).
    • Using the wrong token endpoint: GitHub expects a POST to https://github.com/login/oauth/access_token with an Accept: application/json header; otherwise you’ll receive a URL‑encoded response.
    • Scope errors: Requesting a scope you haven’t enabled in your OAuth app (or that the user denied) will result in a 403 when calling the API.
    • Token expiration: GitHub tokens are long‑lived but can be revoked. Implement graceful fallback (e.g., redirect to login) if an API call returns 401.

    Enhancing Security and Best Practices

    • Store GITHUB_CLIENT_SECRET in environment variables or a secret manager; never hard‑code.
    • Use https in production. OAuth redirects over plain HTTP expose the code and can be intercepted.
    • Set a short session.permanent lifetime and rotate the state token on each auth attempt.
    • Limit scopes to the minimum required. For read‑only operations, use read:user instead of repo.
    • Validate the access_token by calling GET https://api.github.com/user before storing it in the session.

    Testing the Flow Locally

    Running the Flask app on

  • Python Google Oauth2 Login Integration

    Python Google OAuth2 login integration is one of the most requested features for modern web applications. By allowing users to sign in with their Google accounts, developers can boost conversion rates, reduce password fatigue, and leverage Google’s robust security infrastructure. In this guide we’ll walk through everything you need to know to implement a seamless Google OAuth2 login flow in a Python web app—covering setup in the Google Cloud Console, configuring Flask (or Django) back‑ends, handling tokens securely, and troubleshooting common pitfalls. Whether you’re building a small prototype or a production‑grade service, the step‑by‑step instructions below will get you up and running quickly.

    Why Choose Google OAuth2 for Python Applications?

    • Trusted security: Google handles authentication, multi‑factor verification, and account recovery.
    • Reduced friction: Users can sign in with a single click, increasing signup completion rates.
    • Rich user profile data: Access to email, name, picture, and custom scopes for Google APIs.
    • Scalable and compliant: Built on OAuth 2.0 standards, meeting GDPR and CCPA requirements.

    Prerequisites Before You Start

    1. A Google Cloud Platform (GCP) project with the OAuth consent screen configured.
    2. Python 3.8+ installed locally or on your server.
    3. A web framework such as Flask or Django. This tutorial uses Flask for simplicity.
    4. Basic knowledge of HTTP, redirects, and JSON handling.

    Step 1: Create OAuth 2.0 Credentials in Google Cloud Console

    1.1 Enable the Google Identity Services API

    Navigate to the APIs & Services Library and enable Google Identity Services. This API provides the endpoints needed for token exchange and user info retrieval.

    1.2 Configure the OAuth consent screen

    Go to OAuth consent screen and fill in:

    • App name, support email, and developer contact information.
    • Scopes you intend to request (e.g., email, profile, openid).
    • Authorized domains (your production domain and any local development URLs like localhost).

    1.3 Generate client ID and client secret

    Under Credentials → Create Credentials → OAuth client ID, select Web application. Add the following Authorized redirect URIs (adjust the port if needed):

    http://localhost:5000/auth/callback
    https://yourdomain.com/auth/callback
    

    Save the generated Client ID and Client Secret. You’ll need them in your Python code.

    Step 2: Set Up the Python Environment

    2.1 Install required packages

    pip install Flask requests-oauthlib python-dotenv
    

    The requests-oauthlib library simplifies the OAuth 2.0 flow, while python-dotenv helps keep secrets out of source control.

    2.2 Create a .env file

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

    Load these variables in your Flask app using python-dotenv.

    Step 3: Implement the OAuth Flow in Flask

    3.1 Basic Flask app skeleton

    from flask import Flask, redirect, url_for, session, request, jsonify
    from requests_oauthlib import OAuth2Session
    from dotenv import load_dotenv
    import os
    
    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
    SCOPE = ['openid', 'https://www.googleapis.com/auth/userinfo.email',
             'https://www.googleapis.com/auth/userinfo.profile']
    

    3.2 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',
            prompt='select_account'
        )
        # Store state in session to protect against CSRF
        session['oauth_state'] = state
        return redirect(authorization_url)
    

    3.3 Callback route – exchange code for tokens

    @app.route('/auth/callback')
    def callback():
        google = OAuth2Session(
            client_id=os.getenv('GOOGLE_CLIENT_ID'),
            redirect_uri=url_for('callback', _external=True),
            state=session.get('oauth_state')
        )
        token = google.fetch_token(
            TOKEN_URL,
            client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
            authorization_response=request.url
        )
        # Save token securely (e.g., in a server‑side session or DB)
        session['oauth_token'] = token
    
        # Retrieve user profile
        resp = google.get(USER_INFO_URL)
        user_info = resp.json()
        # Example: store user info in session
        session['user'] = {
            'id': user_info['sub'],
            'email': user_info['email'],
            'name': user_info['name'],
            'picture': user_info['picture']
        }
        return redirect(url_for('profile'))
    

    3.4 Protected 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.5 Logout route

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

    Step 4: Secure Token Management

    • Never expose the client secret to the browser. Keep it on the server side only.
    • Store access and refresh tokens in an encrypted database if you need long‑term access.
    • Validate the id_token signature using Google’s public keys (available at https://www.googleapis.com/oauth2/v3/certs) for added security.
    • Implement token refresh logic: when the access token expires, use the refresh token to obtain a new one without prompting the user again.

    Step 5: Extending the Integration – Accessing Google APIs

    Once you have a valid access token, you can call any Google API that matches the scopes you requested. For example, to list the authenticated user’s Google Drive files:

    import requests
    
    def list_drive_files():
        token = session.get('oauth_token')
        headers = {'Authorization': f"Bearer {token['access_token']}"}
        drive_api = 'https://www.googleapis.com/drive/v3/files'
        response = requests.get(drive_api, headers=headers, params={'pageSize': 10})
        return response.json()
    

    Common Errors and How to Fix Them

    Invalid redirect URI

    Google will reject the request if the redirect_uri does not exactly match one of the URIs you entered in the Cloud Console. Double‑check for trailing slashes, HTTP vs. HTTPS, and port numbers.

    CSRF state mismatch

    If the state stored in the session differs from the one returned by Google, the callback will raise a InvalidStateError. Ensure you store session['oauth_state'] before the redirect and retrieve the same value in the callback.

    Expired or revoked token

    When an access token expires, Google returns a 401 Unauthorized. Use the stored refresh_token to request a new access token, or redirect the user to the login flow again if the refresh token is also invalid.

    Testing Locally vs. Production

    • Local development: Use http://localhost:5000 as an authorized domain. Some browsers block third‑party cookies on localhost; consider using SameSite=None; Secure flags only in production.
    • Production: Enforce HTTPS, set SESSION_COOKIE_SECURE = True in Flask, and consider using a reverse proxy (e.g., Nginx) to terminate SSL.
    • Enable Google’s test users feature while the app is in “Testing” mode to avoid a public verification process.

    Performance Tips for High‑Traffic Sites

    1. Cache the Google public keys for token verification (they rotate about once per hour).
    2. Store user sessions in a fast key‑value store like Redis instead of server memory.
    3. Limit the