Skip to content
KleinFrom242Public

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Flask Example Project

This is a small demonstration Flask app that shows several common web app features you can point out to someone learning the basics:

  • A simple login flow using environment-backed credentials and flask-login for session management.
  • CSRF protection via Flask-WTF (with the webhook endpoint intentionally CSRF-exempt).
  • A webhook receiver endpoint that can verify an HMAC-SHA256 signature.
  • An example API endpoint protected by a simple token header.
  • Rate limiting using Flask-Limiter (in-memory by default for demo).
  • A small client script and a UI demo to show the server performing an external GET request.

This repo is for demonstration only. Do not copy these auth patterns directly into production.

Quick setup

  1. Create and activate a virtual environment (macOS / zsh example):
python3 -m venv .venv
source .venv/bin/activate
  1. Install dependencies:
pip install -r requirements.txt
  1. Copy the example env and edit values:
cp .env.example .env
# edit .env and set SECRET_KEY, WEBHOOK_SECRET, etc.
  1. Run the app:
FLASK_APP=app FLASK_ENV=development flask run

Now open http://127.0.0.1:5000 in your browser.

Environment variables

  • SECRET_KEY — Flask session/CSRF secret. Set to a long random string.
  • DEMO_USER / DEMO_PASS — Simple demo credentials used by the /login form.
  • API_KEY — Token expected by the /api/data endpoint when called with X-API-KEY header or ?api_key= query param.
  • WEBHOOK_SECRET — If set, the /webhook endpoint will validate HMAC-SHA256 signatures.

All variables are read using python-dotenv (the .env file is loaded automatically by the app during startup).

Endpoints (what they do)

All example requests return JSON (or HTML for pages) and are intentionally simple.

  • GET / — Home page (rendered HTML). Shows links and a demo widget to trigger a server-side GET.

  • GET, POST /login — Simple login form. Use DEMO_USER / DEMO_PASS from .env to authenticate. On success the session is established via flask-login and the user can access protected pages.

  • GET /logout — Logs out the current session and clears the session cookie.

  • GET /protected — A route decorated with @login_required (only accessible after login).

  • POST /webhook — Webhook receiver. Characteristics:

    • Expects a JSON body (Content-Type: application/json).
    • CSRF is exempted (webhooks are server-to-server and don't use browser cookies).
    • If WEBHOOK_SECRET is set, the endpoint verifies an HMAC-SHA256 signature using the raw request body.
    • Supported signature headers (checked in this order): X-Signature, X-Hub-Signature-256, X-Hub-Signature.
      • The header may be sha256=<hex> or just <hex> — the code normalizes either form.
    • On signature mismatch the endpoint returns HTTP 401. On success it returns { "status": "received" }.

    Example curl (no signature):

    curl -X POST -H "Content-Type: application/json" -d '{"hello": "world"}' http://127.0.0.1:5000/webhook

    Example curl with signature (shell example computing HMAC-SHA256):

    SECRET=webhook-secret
    BODY='{"hello":"world"}'
    SIG=$(printf "%s" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | xxd -p -c 256)
    curl -X POST -H "Content-Type: application/json" -H "X-Signature: sha256=$SIG" -d "$BODY" http://127.0.0.1:5000/webhook
  • GET /api/data — Example API endpoint protected by a token. Characteristics:

    • Requires X-API-KEY header or ?api_key= query parameter that matches API_KEY from .env.
    • Rate-limited by the configured limiter.
    • Returns a JSON payload that includes the current session username (if any).

    Example curl:

    curl -H "X-API-KEY: secret-token" http://127.0.0.1:5000/api/data
  • GET /demo/get — Server-side demo route that performs a GET to another URL and returns the result.

    • Query params:
      • url — target URL (default https://httpbin.org/get)
      • api_key — optional key sent as X-API-KEY header to the target
    • This is the server-side operation triggered by the UI demo on the home page.

    Example (server will request httpbin and return its JSON):

    curl "http://127.0.0.1:5000/demo/get?url=https://httpbin.org/get"

UI demos and scripts

  • templates/index.html includes a small demo card where you can enter a URL and optional API key and click Send GET. That triggers a call to the server's /demo/get route and displays the server's response.
  • scripts/send_get_example.py is a tiny CLI client that performs the same GET (useful to show how to call an API from Python).

How the webhook signature is verified (details)

  1. The server reads the raw request body bytes (request.get_data()), not the parsed JSON. This is important because the HMAC must operate on the exact byte sequence the sender hashed.
  2. The server expects an HMAC-SHA256 hex digest created using the shared WEBHOOK_SECRET and the raw payload.
  3. Header formats supported:
    • X-Hub-Signature-256: sha256=<hex> (common for GitHub-style signatures)
    • X-Signature: <hex> or X-Hub-Signature: <hex> (also accepted)
  4. The server computes hmac.new(secret, payload_bytes, hashlib.sha256).hexdigest() and uses hmac.compare_digest to avoid timing attacks.

CSRF and webhooks

CSRF protection is intended to protect browser-based, cookie-bearing sessions from cross-site requests. Webhooks are server-to-server and normally not run with a browser context, so the /webhook route is explicitly exempt from CSRF checks in this demo. Do not remove signature verification in real systems.

Rate limiting

Flask-Limiter is configured with default in-memory storage for simplicity; it prints a warning on startup. For production use, configure a persistent backend (Redis, Memcached, etc.) as described in the Flask-Limiter docs.

Security notes and improvements (do not use as-is in production)

  • Replace environment-backed plain-password demo auth with a proper user model and password hashing (bcrypt/argon2).
  • Use a secure storage backend for rate limiting and for storing secrets.
  • Use an Authorization: Bearer <token> style for APIs and rotate long-lived tokens.
  • Add replay protection for webhooks (timestamps + allowed skew) and log delivery metadata.

Troubleshooting

  • If clicking the demo button shows no output, open the browser DevTools console and Network tab to see if the fetch to /demo/get succeeded and what the response was.
  • Check the Flask server console where you ran flask run for logged errors such as connection timeouts or exceptions (demo_get: prints are included in the server logs for debugging).

Next steps / Demo ideas

  • Add a small scripts/send_webhook.py script that signs payloads using WEBHOOK_SECRET so you can demo a valid/invalid signature.
  • Add unit tests for the webhook signature verification helper.
  • Wire in a persistent limiter backend (Redis) and add environment-specific configs.

If you'd like, I can add the send_webhook.py demo script and a small test that demonstrates a valid signed request and a rejected request with an invalid signature.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages