"""Shared auth utilities — centralized login_required decorator."""
from functools import wraps
from flask import g, redirect, request, session, url_for
def login_required(f):
"""Decorator that requires the user to be logged in.
Shared across all blueprints. Import from app.auth_utils instead
of defining locally. For JSON API endpoints, returns 401.
Uses request.is_json (which validates both Content-Type and parseable
JSON body) or Accept header, instead of trusting the spoofable
Content-Type header.
"""
@wraps(f)
def decorated(*args, **kwargs):
if "user_id" not in session:
# API endpoints expect JSON 401 — check request.is_json (validates body)
# or Accept header, not the spoofable Content-Type alone
if request.is_json or request.accept_mimetypes.best == "application/json":
return {"error": "Authentication required"}, 401
return redirect(url_for("auth.login", next=request.url))
g.user_id = session["user_id"]
return f(*args, **kwargs)
return decorated