Files
emaui/libs/auth/src/lib/utils/fayda-session.ts
mihretue c4c84abc66 refactor(signup): drive Fayda through register-with-fayda
Follows the API back to a single endpoint. The page posts { action: 'start' }
to open the attempt, the callback page posts { action: 'verify', ... } to get
the verified identity, and the existing signup submission is unchanged.

Drops the post-signup link call: there is no longer a link endpoint, and the
account is created by the signup endpoint that already owns user creation.
2026-08-25 13:01:40 +00:00

80 lines
2.2 KiB
TypeScript

/**
* 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<T>(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<FaydaRequest>(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<FaydaResult>(RESULT_KEY),
clearResult: () => clear(RESULT_KEY),
};