fix(auth): persist session in localStorage so login survives the language switch
The language switch is a full-page navigation to a separate bundle (nl at /, en at /en/); sessionStorage's per-tab semantics dropped the login across it. localStorage is unambiguously shared same-origin and survives the hard navigation. Keeps G1 (naam only, never the BSN). Trade-off: the demo session now survives tab close — a real portal keeps auth in an httpOnly cookie/token. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ const STORAGE_KEY = 'session-v1';
|
||||
unused after login; only `naam` is shown in the chrome. */
|
||||
function restore(): Session | null {
|
||||
try {
|
||||
const raw = sessionStorage.getItem(STORAGE_KEY);
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as Partial<Session>;
|
||||
return typeof parsed?.naam === 'string' ? { bsn: '', naam: parsed.naam } : null;
|
||||
@@ -24,10 +24,12 @@ function restore(): Session | null {
|
||||
* Holds the current session for the whole app. Because it is providedIn:'root'
|
||||
* there is exactly one instance — every component that injects it sees the same
|
||||
* session signal, so logging in is instantly visible everywhere (the guard, the
|
||||
* header, etc.). The session is mirrored to sessionStorage so a refresh or a
|
||||
* deep-link to a protected route keeps you logged in; it clears when the tab
|
||||
* closes. ponytail: sessionStorage, not localStorage — no cross-tab sync, which
|
||||
* matches a single-session portal.
|
||||
* header, etc.). The session is mirrored to localStorage so a refresh, a deep-link,
|
||||
* or the full-page navigation the language switch performs (nl at `/` ⇄ en at `/en/`,
|
||||
* separate bundles) keeps you logged in. ponytail: localStorage, not sessionStorage —
|
||||
* sessionStorage's per-tab clearing dropped the login on the cross-bundle language
|
||||
* switch. Trade-off: the demo session now survives tab close; a real portal keeps auth
|
||||
* in an httpOnly cookie/token, not web storage.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SessionStore {
|
||||
@@ -41,8 +43,8 @@ export class SessionStore {
|
||||
effect(() => {
|
||||
const s = this._session();
|
||||
// G1: persist only `naam` — never write the BSN (national ID) to storage.
|
||||
if (s) sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ naam: s.naam }));
|
||||
else sessionStorage.removeItem(STORAGE_KEY);
|
||||
if (s) localStorage.setItem(STORAGE_KEY, JSON.stringify({ naam: s.naam }));
|
||||
else localStorage.removeItem(STORAGE_KEY);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user