Why does a guest's held campsite selection vanish at sign-in unless the server copies it into the new server-side session record?
answer
- cookie holds a reference, not the data
- new identifier names a new record
- carrying it is code you write
- copy named items, not everything
- destroy the old record afterwards
basics
~20 sBecause the selection is filed server-side under the identifier the visitor had before signing in, and sign-in issues a new one. Carrying it over is an explicit step in the login handler, and not every item should be carried.
solid answer
~40 sAn anonymous visitor already has a server-side session record; the cookie only carries an opaque reference to it. Sign-in issues a **new** identifier, so the request that arrives next names a different record — the guest data is still sitting under the old key until the login handler copies it, or it is deleted with that record. So "the cart survives login" is not a property of sessions; it is code you write. The copy is also a filter rather than a bulk move: the held dates and permits come across because losing them costs the visitor the transaction, the anti-forgery token is re-issued rather than copied because it is bound to the identifier that just changed, and the old record is destroyed afterwards so a stale tab cannot keep writing to it.
code
pseudocode · 7 lineson login_completed(old_record, new_session):
new_session.held_dates = old_record.held_dates # carried: losing it costs the booking
new_session.vehicle_permits = old_record.vehicle_permits
new_session.language = old_record.language # carried: harmless preference
new_session.anti_forgery_token = issue_anti_forgery_token() # re-issued, never copied
# consent choices are NOT copied: the guest record is not evidence of this human
old_record.destroy() # no orphan still accepting writesgo deeper
Recall that the cookie holds only a reference and the data sits in a server-side record. When sign-in issues a new identifier, the old record is still there — it just is not the one being read any more.
Explain the copy as a filter: which items are carried, which are re-issued because they were bound to the old identifier, and why the old record is destroyed rather than left to expire.
Bring up the cases that make it real: a retried sign-in running the handler twice, a stale tab writing to the orphan record, and guest data that should not be carried because the anonymous record is not evidence of a person.
Decide the default: an allowlist of carried items reviewed like any other contract, so the set does not quietly grow as attributes are added and nobody re-asks whether they belong on the authenticated side.
## Where a guest's selection actually lives A visitor walks up to the campsite reservation counter and picks a pitch, three nights and two vehicle permits before anyone has asked who they are. All of that is real state and it has to be somewhere. In a server-side session design it is in a **record on the server**, filed under an opaque identifier; the visitor's browser holds only that identifier, in a cookie. The record is the state, the cookie is the reference to it. That separation is the whole answer to this question. The browser is not carrying the selection, so nothing the browser does preserves it; only the record does, and the record is reachable through exactly one value. ## What sign-in changes When the visitor identifies themselves and completes the login, the server issues a **new session identifier** for the authenticated session. That is standard practice and it is not this decision — take it as given. What it means for the selection is mechanical: - the request after sign-in presents the new identifier; - the new identifier names a different record — a fresh one; - the guest's selection is still filed under the old identifier, untouched; - when the old record is cleaned up, the selection goes with it. So the selection disappears not because anything deleted it, but because nothing brought it along. Carrying guest state across sign-in is **an explicit step in the login handler**, and a team that has never written that step has a service where every guest who signs in loses their work — usually discovered the week after two-step login is added, because that is when more people sign in mid-flow. ## The copy is a filter, not a bulk move It is tempting to move every attribute across in one loop. Each item deserves a decision: | Guest-session item | Fate at sign-in | Why | |---|---|---| | Held pitch, dates, vehicle permits | **carry** | Losing it costs the visitor the transaction and they will not redo it | | Display language, accessibility preference | **carry** | Harmless preference, no authority attached | | Anti-forgery token | **re-issue** | It is bound to the session identifier that just changed, so copying it carries a value tied to a session that no longer exists | | The pre-authentication handle from the login itself | **destroy** | Its attempt is over; it must not outlive the sign-in it completed | | Anything the signed-in account already has its own copy of | **the account's copy wins, or ask** | The account's data was saved by a proven human; the guest record's was not | The last row is where this stops being a checklist. A guest record is not evidence of a person — at a counter terminal used by several people across a shift, the selection sitting in it may belong to whoever was there before. That is why identity-bearing guest data, such as recorded consent choices or a typed email address, is carried only when the anonymous record can be shown to have been the same human, which in that setting it usually cannot. ## Doing the copy Three rules keep the step boring: 1. **Copy named items, not everything.** An explicit list is readable, reviewable, and it does not silently start carrying whatever attribute someone adds next year. 2. **Destroy the old record afterwards.** If it survives, a tab the visitor still has open keeps writing to a record nobody will ever read again, and the visitor sees their later changes vanish. 3. **Make it safe to run twice.** A retried or double-submitted sign-in can run the handler again, and "copy the cart" run twice is how a visitor ends up holding two of everything. ## What this is not This is not about the cookie's own attributes, and it is not about whether the identifier should change at sign-in — it does, and that rule is settled elsewhere. It is only about what happens to state that existed on the anonymous side of that change. The interview version of this question is short, and the answer that lands is: *the state is filed under the old identifier, so it moves only if I move it, and I move it item by item.*
- Why not simply keep the same session identifier at sign-in, so nothing needs copying?Because the identifier is re-issued at authentication for reasons that have nothing to do with the cart, and that rule is not negotiable to save a copy step. Treat the change as fixed and design the migration around it; the copy is a handful of lines and it is the part you control.
- Should the old anonymous record be destroyed immediately or left to expire?Destroyed as part of the login handler. Leaving it to expire means a tab the visitor still has open keeps writing to a record nothing reads, so their later edits appear to vanish, and it leaves a second record naming the same selection for as long as the clock runs.
- What if a guest never signs in at all?Nothing changes for them: the anonymous record lives on its own clock and expires with the selection in it. The migration question only arises at the moment the identifier changes, which is why this is a sign-in problem rather than a cart problem.
saying these in an interview costs you the question
- The cart is in the cookie, so sign-in cannot lose it.
- Copy every attribute across in one loop, it is simpler.
- Carry the anti-forgery token over so open forms keep working.
- Leave the old anonymous record alone; it expires anyway.
- Guest state survives login automatically, that is what sessions do.