/** * The Fayda round trip leaves the app entirely, so the little state that has to * survive it lives in sessionStorage: same tab, same origin, gone when the tab * closes. * * Nothing secret is kept here. The `transactionToken` is signed by the API and * useless without it — the PKCE verifier, the nonce and the client key never * leave the backend. */ const REQUEST_KEY = 'fayda:request'; const RESULT_KEY = 'fayda:result'; export interface FaydaRequest { transactionToken: string; state: string; } export interface FaydaPrefill { email?: string; phoneNumber?: string; nameEn?: string; nameAm?: string; /** Shown for context only — the signup form has no field for these. */ gender?: string; address?: string; } /** Shape of `POST /auth/register-with-fayda` with `action: "verify"`. */ export interface FaydaResult { identity: FaydaPrefill; faydaVerified: boolean; /** Signup fields Fayda vouched for. */ verifiedFields: string[]; /** Prefilled fields already taken by another account. */ conflicts: string[]; } // Private browsing and locked-down browsers can throw on access, and a failure // here should degrade to "no Fayda prefill", never break the signup page. function read(key: string): T | null { try { const raw = sessionStorage.getItem(key); return raw ? (JSON.parse(raw) as T) : null; } catch { return null; } } function write(key: string, value: unknown): void { try { sessionStorage.setItem(key, JSON.stringify(value)); } catch { /* nothing to do — the flow reports a generic failure instead */ } } function clear(key: string): void { try { sessionStorage.removeItem(key); } catch { /* ignore */ } } export const faydaSession = { saveRequest: (request: FaydaRequest) => write(REQUEST_KEY, request), takeRequest: (): FaydaRequest | null => { const request = read(REQUEST_KEY); // Single use: a stale token would otherwise be replayed against a fresh // callback and fail with a confusing "session expired". clear(REQUEST_KEY); return request; }, saveResult: (result: FaydaResult) => write(RESULT_KEY, result), peekResult: (): FaydaResult | null => read(RESULT_KEY), clearResult: () => clear(RESULT_KEY), };