From aca2e4758375e333d40c9dc3926b4e3c9d8c4368 Mon Sep 17 00:00:00 2001 From: Nguyen Ngo Date: Sat, 2 May 2026 08:37:27 -0400 Subject: [PATCH] 05/02/2026 Updates for iPad app: Phase 1 - fix token getting issue 2 --- app/__init__.py | 22 +++++++++++++++++----- app/api/__init__.py | 10 ++++++---- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 390dd32..148e247 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -147,12 +147,24 @@ def create_app(config_name='default'): app.register_blueprint(customers.bp) app.register_blueprint(scheduled_reports.bp) - # ── Mobile API (Phase 7) ───────────────────────────────────────────────── - # The /api/v1 blueprint uses JWT Bearer tokens — no CSRF cookies needed. - # Exempt it from CSRFProtect before registering so POST /api/v1/* routes - # are never rejected for a missing CSRF token. + # ── Mobile API (Phase 7 / Phase A) ────────────────────────────────────── + # The /api/v1 blueprint group uses JWT Bearer tokens — no CSRF cookies needed. + # + # Flask-WTF's _is_exempt() checks whether the *leaf* blueprint object + # (e.g. api_auth, api_facilities) is in _exempt_blueprints. Exempting + # the parent api_bp alone does NOT cascade to its sub-blueprints because + # request.blueprint returns the dotted child name ('api.api_auth'), and + # current_app.blueprints maps that to the child Blueprint object — which + # is never equal to the parent object in the exempt set. + # + # Fix: import every child blueprint object and exempt each one explicitly. from app.api import register_api, api_bp - csrf.exempt(api_bp) + from app.api.auth import bp as _api_auth_bp + from app.api.facilities import bp as _api_facilities_bp + from app.api.templates import bp as _api_templates_bp + csrf.exempt(_api_auth_bp) + csrf.exempt(_api_facilities_bp) + csrf.exempt(_api_templates_bp) register_api(app) # ── Error handler: 413 Request Entity Too Large ─────────────────────── diff --git a/app/api/__init__.py b/app/api/__init__.py index 935b47a..7ef01c6 100644 --- a/app/api/__init__.py +++ b/app/api/__init__.py @@ -45,17 +45,19 @@ def register_api(app): register api_bp on the Flask app. Called once from create_app() in app/__init__.py. + + NOTE: CSRF exemption for each sub-blueprint is handled in app/__init__.py + before this function is called, because csrf.exempt() must receive the + child Blueprint object directly — exempting the parent api_bp does not + cascade to its sub-blueprints. """ - # ── Phase 1 (Web): Auth ────────────────────────────────────────────── + # ── Phase 7 (Web): Auth ────────────────────────────────────────────── from app.api.auth import bp as auth_bp api_bp.register_blueprint(auth_bp) # ── Phase A (iPad): Reference data ────────────────────────────────── from app.api.facilities import bp as facilities_bp from app.api.templates import bp as templates_bp - from app import csrf - csrf.exempt(facilities_bp) - csrf.exempt(templates_bp) api_bp.register_blueprint(facilities_bp) api_bp.register_blueprint(templates_bp)