Ask

Forms started failing CSRF verification the moment I put a reverse proxy in front of the app

The check that is failing is origin comparison, and the proxy broke it by changing what the application sees.

CSRF protection on a form post compares where the browser says the request came from — the Origin or Referer header — against where the application believes it is running. That second value is assembled from the request: the host header and whether the connection was secure.

Behind a proxy, the browser talks HTTPS to the proxy and the proxy talks plain HTTP to your app. So the application sees an unencrypted request and concludes it is running at http://..., while the browser reports an origin of https://.... The strings differ, and the request is rejected.

That is why nothing you changed in the form matters, and why it appeared exactly when the proxy did.

30 · in/fullstack ·

My recording project will not open and I have no other copy — what are the recovery options?

The part that stops this happening again, and it is not "remember to back up":

Save versioned files, not one file. Save as a new numbered version at every meaningful point. A corrupt file then costs you one session rather than the project, and it costs nothing but disk.

Get the project folder into something that keeps history automatically. A sync service with version history, or a scheduled snapshot. The point is that it happens without you deciding to do it, because the sessions where you forget are the sessions that crash.

Export a rough mix at the end of every session. A single audio file of where you got to. It is not editable and it means the work is never entirely gone, and it takes thirty seconds.

The last one has saved more people than any backup strategy, because it is small enough that everybody actually does it.

22 · in/home-recording ·

The OAuth provider rejects my callback URL because it points at localhost

For development, where you genuinely do not have a public HTTPS address, the options in order of how much I like them:

A tunnelling service. Gives you a public HTTPS URL forwarding to your local port. Register that as the callback and everything behaves as it will in production. Some of them give an unstable hostname on the free tier, which means re-registering the callback constantly — a fixed subdomain is worth paying for if you do this often.

A separate application registration for development, with its own callback, so you are not editing the production one and risking leaving it pointed at a tunnel.

A local domain with a real certificate, mapped in your hosts file. More setup, and it works offline and never expires mid-demo.

What I would avoid is disabling certificate or redirect validation to make it work locally, because that difference between environments is exactly where the bug you ship comes from.

22 · in/sessions-vs-jwt ·

What are the sensible front-end options for a server-rendered app in the current landscape?

The middle ground is now well populated and it is where most applications in your position land.

The options, in increasing order of commitment:

1. Sprinkles of JavaScript. A small library for attaching behaviour to markup, or plain modern JavaScript. Fine for a dropdown or a toggle, and it stops scaling once state is shared between parts of a page.

2. HTML over the wire. The server keeps rendering HTML, and a small library swaps fragments in response to interactions. Your templates stay authoritative, there is no duplicated model on the client, and you keep the framework's forms and validation. For live filtering and inline editing this is usually the right answer and it is a remarkably small change.

3. Islands. Server-rendered pages with a few components mounted into them by a real framework. Right when you have a genuinely complex widget — a scheduler, a canvas, a rich editor — inside otherwise ordinary pages.

4. A full single-page application with an API. Right when the whole product is an application rather than a set of pages, or when you need offline, or when a separate mobile client wants the same API anyway.

30 · in/fullstack ·