Hypermedia foundations
The server remains the security boundary
Apply authentication, authorization, validation, CSRF protection, and output escaping to every HTMX endpoint.
HTMX changes how the browser initiates a request. It does not change the server’s security responsibilities. Every route your attributes point at must be safe on its own.
An attacker can copy this request without clicking your button:
<button hx-delete="/tasks/42">Delete</button>
The delete route must independently:
- authenticate the current user
- authorize that user for task
42 - verify CSRF protection for the state-changing request
- validate every submitted value
- perform the operation safely
- escape untrusted values in the returned HTML
Hiding a button is a user-interface decision, not authorization. HX-Request: true, hidden inputs, hx-vals, and IDs in the DOM are all controlled by the client. Never treat them as proof that the request is legitimate.
Return an accurate status code and safe error fragment. A 403 may say the action is unavailable, but it must not reveal another user’s private task or an internal stack trace. I treat HTMX error fragments the same way I treat full-page errors: safe for the current user, no secrets.
CSRF tokens belong in the form or session the same way they always have. HTMX submits forms with the same encoding rules as a normal browser submission, so your existing CSRF middleware should still apply. If it does not, fix the server before blaming HTMX.
As an exercise, send the same request from curl without your page. If the server trusts an HTMX attribute or header that the browser normally supplied, the route has a security bug. Copy the request from DevTools, strip the cookie, change the task ID, and see what happens.
Try this on your own project: pick one state-changing HTMX route and run it through your normal auth and CSRF checks as if it were a plain form post.
Lesson completed