fix: storefront login 403, cookie path, double-storefront URLs, and auth redirects
Some checks failed
CI / ruff (push) Successful in 9s
CI / pytest (push) Failing after 46m52s
CI / validate (push) Successful in 23s
CI / dependency-scanning (push) Successful in 30s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

- Extract store/platform context from Referer header for storefront API requests
  (StoreContextMiddleware and PlatformContextMiddleware) so login POST works in
  dev mode where API paths lack /platforms/{code}/ prefix
- Set customer token cookie path to "/" for cross-route compatibility
- Fix double storefront in URLs: replace {{ base_url }}storefront/ with {{ base_url }}
  across all 24 storefront templates
- Fix auth error redirect to include platform prefix and use store_code
- Update seed script to output correct storefront login URLs
- Add 20 new unit tests covering all fixes; fix 9 pre-existing test failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 12:29:52 +01:00
parent 32e4aa6564
commit f47c680cb8
38 changed files with 759 additions and 165 deletions

View File

@@ -319,10 +319,12 @@ class PlatformContextMiddleware:
path = scope["path"]
host = ""
referer = ""
for header_name, header_value in scope.get("headers", []):
if header_name == b"host":
host = header_value.decode("utf-8")
break
elif header_name == b"referer":
referer = header_value.decode("utf-8")
# Skip for static files
if self._is_static_file(path):
@@ -354,6 +356,23 @@ class PlatformContextMiddleware:
# Detect platform context
platform_context = self._detect_platform_context(path, host)
# For storefront API requests on localhost, the path doesn't contain
# /platforms/{code}/, so extract platform from the Referer header instead.
# e.g., Referer: http://localhost:8000/platforms/loyalty/storefront/FASHIONHUB/...
host_without_port = host.split(":")[0] if ":" in host else host
if (
host_without_port in _LOCAL_HOSTS
and path.startswith("/api/v1/storefront/")
and referer
and platform_context
and platform_context.get("detection_method") == "default"
):
referer_platform = self._extract_platform_from_referer(referer)
if referer_platform:
# Keep the original API path — don't rewrite to the Referer's path
referer_platform["clean_path"] = path
platform_context = referer_platform
if platform_context:
db_gen = get_db()
db = next(db_gen)
@@ -488,6 +507,43 @@ class PlatformContextMiddleware:
return None
@staticmethod
def _extract_platform_from_referer(referer: str) -> dict | None:
"""
Extract platform context from Referer header.
Used for storefront API requests on localhost where the API path
doesn't contain /platforms/{code}/ but the Referer does.
e.g., Referer: http://localhost:8000/platforms/loyalty/storefront/FASHIONHUB/...
→ platform_code = "loyalty"
"""
try:
from urllib.parse import urlparse
parsed = urlparse(referer)
referer_path = parsed.path or ""
if referer_path.startswith("/platforms/"):
path_after = referer_path[11:] # Remove "/platforms/"
parts = path_after.split("/", 1)
platform_code = parts[0].lower()
if platform_code:
logger.debug(
f"[PLATFORM] Extracted platform from Referer: {platform_code}"
)
return {
"path_prefix": platform_code,
"detection_method": "path",
"host": parsed.hostname or "",
"original_path": referer_path,
"clean_path": "/" + parts[1] if len(parts) > 1 and parts[1] else "/",
}
except Exception as e:
logger.warning(f"[PLATFORM] Failed to extract platform from Referer: {e}")
return None
def _is_static_file(self, path: str) -> bool:
"""Check if path is for static files."""
path_lower = path.lower()