Cookie session
The cookie
Name: sos_portal
Value: the raw token (same string as in /p/{token} URL)
Set automatically on every successful /p/{token} hit, by the portal
landing handler in src/routes/portal.ts.
sos_portal=<token>; Domain=.stayonthesnow.com; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=63072000Why each attribute
| Attribute | Why |
|---|---|
Domain=.stayonthesnow.com | Survives subdomain consolidation — my., admin., future surfaces can see it |
Path=/ | Available on every page |
HttpOnly | Not readable from JS — defense-in-depth against XSS |
Secure | Only sent over TLS |
SameSite=Lax | Still sent on top-level navigations from email link clicks |
Max-Age=63072000 | 2 years — long-tail “welcome back, book again” recognition |
The cookie-root flow
/ on my.stayonthesnow.com is the “I lost my email link” landing.
Behavior:
- Read the
sos_portalcookie - If present and resolves to a valid token →
302 /p/{token} - If present but the token is no longer valid → clear the cookie, render the “Find your booking link” welcome
- If absent → render the welcome page (no cookie touched)
So a guest who has visited the portal once on their phone can later
just type my.stayonthesnow.com and land back in their portal — until
the token expires (30 days post-departure) or the cookie is cleared.
Logout
GET /signout clears the cookie (Max-Age=0) and renders a goodbye
page. We don’t currently surface a logout button — guests aren’t
asked to sign out, and the long cookie lifetime serves the
returning-visitor recognition goal.
What about multiple bookings on one device?
A single browser cookie holds one booking’s token. If a guest has multiple stays, whichever portal link they clicked most recently is the one their cookie points at. We can extend this later (multi-stay picker) when there’s a real use case — Bill’s volume is mostly single- stay families.
Marketing signal
The 2-year cookie lifetime exists primarily to recognize a returning
visitor for re-book nudges. The cookie itself doesn’t store anything
beyond the booking-scoped token; if/when we add marketing tracking
we’d add a separate non-HttpOnly cookie with the bare-minimum signal
(e.g. sos_seen=<isoDate>).