19b66b7bbd
RequireCSRF looked up csrf_token by user_id ORDER BY created_at DESC LIMIT 1 — the newest session, not the one whose Bearer token was presented. Two consequences: created_at's 1-second resolution made two same-second sessions a coin-flip (phantom 403s), and conceptually it accepted "any valid CSRF for this user" rather than the one bound to this session. Now queried by token_hash = SHA256(bearer) AND user_id. Authenticate already located this row + checked expiry, so the expiry clause is dropped. Signature unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>