top | item 41193922

A heck of a wild bug chase

66 points| togakangaroo | 1 year ago |georgemauer.net

56 comments

order

jof|1 year ago

It seems to me like the underlying issue was ignoring HTTP semantics and making a state-changing link like a logout link a plain <a> (HTTP GET) and not something like a form submission (HTTP POST).

Having intuition for the foundational layers of our tools saves so much time and future headaches.

togakangaroo|1 year ago

Author of the post here,

There was no form submission, I'm not sure where you got that. There was also no POST. Though yes, I agree that in the core HTTP semantic, you wouldn't want to change state on a GET and that should include not calling `Set-Cookie`. And yet the reality is that that nearly every application - and many popular libraries like auth0 - do in fact set and clear cookies on `GET`.

The issue here was that the `Link` component in NextJs

- does preloading by default (which is a bad idea exactly for the above reason of reality being different from theory)

- doesn't do preloading by default when running on the dev server (so you don't see the error until its deployed)

- because it does preloading directly in javascript, it can't possibly follow the HTTP semantic of not actually applying cookies until later when the cached route is used

Everything else was the wild goose chase bits.

Also I asked claude to criticize the article as a web forum might before publishing, and this is definitely the tone it gave :D

Oh, also, I'm pretty sure I got the part wrong where i was talking about the preload attribute in HTML, but so far no one's noticed. I should correct that.

recursivedoubts|1 year ago

This is a very good example where the HTML extensions that alex proposed here:

https://www.youtube.com/watch?v=inRB6ull5WQ

(TLDW: allow buttons to make HTTP requests; allow buttons & forms to issue PUT, PATCH & DELETE; allow buttons, forms & links to target elements in the DOM by id instead of only iframes)

would improve the web platform. You could have a stand-alone logout button that issues a DELETE to /session or whatever. Nice and clean.

Ethee|1 year ago

Genuine question: How do you believe one should learn these semantics? This is more something I've been pondering myself recently, because I agree with you that the foundational knowledge for our work in any tech stack is usually the most important for understanding higher abstractions. But with so much to know it feels impossible to 'know it all' so to speak especially if you wear more than one specialized hat. Then beyond that even if you're only trying to learn just the foundations how do you know what those foundations are if you're not already inundated in that stack?

This is mostly just my personal ramblings, but I'd be curious other peoples viewpoints on this.

graypegg|1 year ago

To be fair, <a> tags can't send out non-GET requests. Which yes, can be interpreted as "logout controls should be buttons in forms, not links", but I would really like native htmx-like attributes for intractable html elements.

hschne|1 year ago

> I didn’t want to deal with databases.

So instead I used a third party authentication service, store some data in JSON files, and also threw up a lamda gateway to store some more data in Google Sheets?

It's not relevant to the bug hunt, but I'm genuinely intrigued. Is this approach considered easier to work with than using a regular ol' DB?

jboogie77|1 year ago

My first thought as well. This is the most complicated stack I’ve seen for something so simple. Just convinced me more to avoid using JavaScript as a backend

williamdclt|1 year ago

> It is wild how decisions made in one part of a technical stack can manifest at another point in time, in another place in the stack, and in such a convoluted manner.

While this isn't something that _only_ happens in modern javascript, it certainly is a pattern. These bugs are convoluted and difficult to debug because the technologies are convoluted, stacked on top of each other compounding the bugs, and devs do not understand the underlying platform.

Honestly, it's once-again a good case study for why I'd stay from NextJS or "modern JS" devs (despite being in this ecosystem myself, Node/React/RN):

- NextJS, one of the most modern techs in wide use, makes debugging _harder_ than vanilla JS?? This is crazy - Reimplementing browser behaviour in JS is _exactly_ what I would expect to be the root cause of various difficult-to-debug-and-to-fix bugs down the line - Using GET for a logout is a misunderstanding of HTTP semantics. This could have broken in other ways (eg integrating turbolinks in the app).

Well done for debugging and fixing this, but honestly... this doesn't speak to the strength of the technology choices or the author's understanding of the platform

andrewfromx|1 year ago

I always do <a href="#" id="logout">logout</a> so there is no url to accidentally GET call anyways.

whbrown|1 year ago

Why make it a link if you aren't linking to anything?

danjl|1 year ago

Authentication is a major hurdle. Back in the days of desktop software, there was no authentication. Mobile apps can often avoid authentication too. Despite decades of web coding, and lots of "this authentication system will make life easy" claims, it is still hard and easy to mess up.

theamk|1 year ago

it's impossible to avoid authentication once you start sharing data between systems though. This includes basic stuff like "I only want to share the list with our graduates", as well things like "those preferences should be the same on every device which user X owns".

throw156754228|1 year ago

OP learnt about idempotency in http the hard way. However the post reminded me that I don't particularly like this hydration step of NextJS apps where there is javascript executing that is difficult if not impossible to step debug.

langsoul-com|1 year ago

So would this simply work if the Link component from nextjs wasn't used?

kaoD|1 year ago

Yes but the underlying problem would still be there, lurking for the future. If e.g. I had a browser extension to prefetch links (for faster navigation) the same issue would be present.

The problem is logging out on a GET request, as discussed in current top comment. It's just semantically incorrect and many tools will (correctly) assume GET requests don't have side-effects (in HTTP's terms, it's a safe method).

E.g. it's very easy to have a GET request cached by mistake (and I've seen some faulty proxies do that, completely ignoring the upstream cache-control).

This is not a problem on Next or its Link component. It's on op's code (and maybe auth0-nextjs allowing logout on GET requests).

realxrobau|1 year ago

So, in summary, because you added a whole bunch of stuff that didn't need to be there, it broke. Colour me surprised.

It sounds like this could be implemented almost completely without any of that, especially as you were using JavaScript for the data.

All I can hope is that you've learnt a lesson about unnecessary overcomplication.