Debug the web path
Reproduce the request with curl
Copy the essential HTTP request outside the browser and remove headers until only the failing contract remains.
10 minute lesson
A failing request seen in the browser has three suspects: your frontend code, the browser itself, and the server. curl separates server behavior from browser UI and frontend code. If curl gets the same failure, the frontend is innocent, and you just saved hours in the wrong layer.
Build the request from scratch
DevTools offers “Copy as cURL”, but the copied command drags along a dozen headers and every cookie. A copied request can still include unnecessary or secret browser state. My advice is to go the other way: start minimal and add only what the failure needs.
Start with a minimal request:
curl --verbose --fail-with-body \
--header 'Content-Type: application/json' \
--data '{"email":"[email protected]"}' \
http://127.0.0.1:3000/api/login
--verbose prints the full exchange — request headers out, response headers in — so you see exactly what the server received and answered. --fail-with-body makes curl exit non-zero on HTTP errors while still printing the error body, which is where the useful message usually lives.
Compare status, headers, and body with the browser request. Three outcomes, three conclusions:
curl fails the same way -> server-side bug, debug the backend
curl succeeds -> the difference is browser state: cookies,
auth, Origin, or frontend code
curl fails differently -> compare the two requests header by header
Add differences one at a time
When curl succeeds but the browser fails, the cause is in whatever the browser sends that you did not. Add the browser’s headers one at a time — the session cookie, then Origin, then any custom header — rerunning after each. The header that flips curl from success to failure names the broken contract.
Add authentication only through a disposable credential when the endpoint requires it. A lab account token is fine; your own production session is not.
Remove copied cookies and tokens before saving or sharing the command. A curl command pasted into a ticket is effectively a stored credential if it embeds a live session — treat it like one.
Lesson completed