2. Security setup: CSRF protection

Before the dashboard creates playlists, syncs data, or clears the snapshot library, it needs a security baseline for every form submission. This page installs Flask-WTF, enables global CSRF protection, and shows the token pattern the form and AJAX pages will reuse.

Before building forms, you need protection against Cross-Site Request Forgery (CSRF) attacks. Without CSRF tokens, malicious websites can trick authenticated users into performing unwanted actions. A hidden form on evil-site.com could trigger your /settings/clear route, deleting all their data without their knowledge.

Flask-WTF provides automatic CSRF protection. Install it alongside your other dependencies:

Terminal
pip install Flask-WTF

Enable CSRF protection globally in your app.py file. Add these imports and configuration at the top of your application:

app.py
from flask import Flask, render_template, redirect, url_for, session, request, flash
from flask_wtf.csrf import CSRFProtect
import sqlite3
import os
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'dev-secret-key-change-in-production')

# Enable CSRF protection for all POST/PUT/PATCH/DELETE requests
csrf = CSRFProtect(app)

# Database configuration
DATABASE_PATH = 'music_time_machine.db'

# Your routes follow below...

That's the entire backend setup. Flask-WTF now requires a CSRF token for every form submission. GET requests (like displaying pages) don't need tokens because they shouldn't modify data anyway. POST requests without valid tokens will be rejected with a 400 Bad Request error.

How CSRF protection works

When Flask renders a template with a form, csrf_token() generates a unique, unpredictable token tied to the user's session. This token gets embedded in a hidden form field. When the form submits, Flask-WTF verifies that the token matches the session.

Malicious sites can't access this token due to browser same-origin policies. They can't read your cookies, can't call csrf_token() on your domain, and can't inspect your rendered HTML. Without the token, their forged requests fail validation.

This protection is automatic once enabled. You just need to include {{ csrf_token() }} in every form's HTML, which you'll do in the upcoming sections.

CSRF tokens in AJAX requests

When you upgrade the Playlist Manager to use AJAX later in this chapter, you'll need to include the CSRF token in the request headers. Flask-WTF looks for tokens in either form data or the X-CSRFToken HTTP header. For AJAX, you'll extract the token from a meta tag and attach it to fetch requests. The implementation details come when you upgrade the Playlist Manager to AJAX.