Review
Drop CSRF checks on KilnQueue shelf-release API
Member SPA and api.kilnqueue.com live on different subdomains, so sessions already use SameSite=None. Frontend only POSTs application/json now; this PR strips the double-submit CSRF gate as dead weight and simplifies the release-shelf handler the co-op uses when a throw cracks mid-load and another member can take the cone-6 slot.
FastAPITier 3securitycsrfcookiesspa
Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.
app/api/kiln/release.py+11-10
| 1 | 1 | from uuid import UUID | |
| 2 | 2 | ||
| 3 | 3 | from fastapi import APIRouter, Depends, Response | |
| 4 | 4 | ||
| 5 | 5 | from app.auth.session import MemberSession, require_member | |
| 6 | - | from app.auth.csrf import require_double_submit_csrf | |
| 7 | 6 | from app.kiln.schedule import release_shelf_slot | |
| 8 | 7 | ||
| 9 | 8 | router = APIRouter(prefix="/api/kiln", tags=["kiln"]) | |
| 10 | 9 | ||
| 10 | + | # SPA posts application/json only. Browsers cannot forge that content-type | |
| 11 | + | # via a cross-site <form>, so double-submit CSRF is unnecessary noise. | |
| 12 | + | # Session cookie remains HttpOnly + Secure + SameSite=None (api.* / app.*). | |
| 11 | - | @router.post("/shelves/{slot_id}/release") | |
| 12 | - | async def release_shelf( | |
| 13 | - | slot_id: UUID, | |
| 14 | - | response: Response, | |
| 15 | - | reason: str = "member_cancel", | |
| 16 | - | reassign_to: UUID | None = None, | |
| 17 | - | session: MemberSession = Depends(require_member), | |
| 18 | - | _csrf: None = Depends(require_double_submit_csrf), | |
| 19 | - | ): | |
| 13 | + | @router.post("/shelves/{slot_id}/release") | |
| 14 | + | async def release_shelf( | |
| 15 | + | slot_id: UUID, | |
| 16 | + | response: Response, | |
| 17 | + | reason: str = "member_cancel", | |
| 18 | + | reassign_to: UUID | None = None, | |
| 19 | + | session: MemberSession = Depends(require_member), | |
| 20 | + | ): | |
| 20 | 21 | result = await release_shelf_slot( | |
| 21 | 22 | slot_id, | |
| 22 | 23 | owner_id=session.member_id, | |
| 23 | 24 | reason=reason, | |
| 24 | 25 | reassign_to=reassign_to, | |
| 25 | 26 | ) | |
| 26 | 27 | return {"slot": result} |