38 lines
2.0 KiB
Markdown
38 lines
2.0 KiB
Markdown
---
|
|
id: TASK-76
|
|
title: 'Persist EncryptID login across subdomains, sessions, and browsers'
|
|
status: Done
|
|
assignee: []
|
|
created_date: '2026-03-01 22:12'
|
|
labels:
|
|
- encryptid
|
|
- auth
|
|
- session
|
|
dependencies: []
|
|
references:
|
|
- shared/components/rstack-identity.ts
|
|
- src/encryptid/server.ts (refresh endpoint accepts expired tokens)
|
|
priority: high
|
|
---
|
|
|
|
## Description
|
|
|
|
<!-- SECTION:DESCRIPTION:BEGIN -->
|
|
EncryptID sessions were lost when navigating between rspace.online subdomains (e.g. demo.rspace.online → cca.rspace.online) because localStorage is per-origin. Sessions also didn't survive token expiry gracefully. Added cross-subdomain cookie persistence alongside localStorage, with automatic refresh of expired tokens via the server.
|
|
<!-- SECTION:DESCRIPTION:END -->
|
|
|
|
## Acceptance Criteria
|
|
<!-- AC:BEGIN -->
|
|
- [ ] #1 Session persists when navigating between *.rspace.online subdomains
|
|
- [ ] #2 Session survives browser close/reopen (30-day cookie)
|
|
- [ ] #3 Expired tokens auto-refresh via server before being discarded
|
|
- [ ] #4 Sign Out clears both localStorage and cookie
|
|
- [ ] #5 Code that directly reads localStorage still works via early cookie→localStorage sync
|
|
<!-- AC:END -->
|
|
|
|
## Final Summary
|
|
|
|
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
|
Added cross-subdomain cookie (`eid_token`, `domain=.rspace.online`, 30-day max-age, `SameSite=Lax`, `Secure`) to `rstack-identity.ts`. Three layers of persistence:\n\n1. **Cookie helpers** — `_setSessionCookie()`, `_getSessionCookie()`, `_removeSessionCookie()` handle domain-wide cookie\n2. **`getSession()` fallback** — tries localStorage first, falls back to cookie, restores to localStorage for fast access\n3. **`#refreshIfNeeded()` upgrade** — attempts server refresh for expired tokens before giving up; server accepts expired tokens via `{ exp: false }`\n4. **Early IIFE sync** — at module load time, syncs cookie→localStorage so direct `localStorage.getItem()` callers (WebSocket auth, sync, shell scripts) see the session\n\nCommit: ef1d93d. Merged dev→main, pushed to Gitea.
|
|
<!-- SECTION:FINAL_SUMMARY:END -->
|