@adonis-agora/authkit-react
Version:
Frontend ergonomics over AuthKit for AdonisJS + Inertia + React apps: a typed useAuth() hook, role-gating hooks and gating components.
69 lines (68 loc) • 2.51 kB
JavaScript
import { useEffect, useRef } from 'react';
import { loadStartAuthentication } from '../passkey/authenticate.js';
export function usePasskeyAutofill(options) {
const { optionsUrl, verifyUrl, onSuccess, csrfToken, enabled = true } = options;
const abortRef = useRef(null);
useEffect(() => {
if (!enabled)
return;
if (typeof window === 'undefined' || typeof navigator === 'undefined')
return;
if (!window.PublicKeyCredential)
return;
let cancelled = false;
const ac = new AbortController();
abortRef.current = ac;
const run = async () => {
try {
const supported = typeof PublicKeyCredential.isConditionalMediationAvailable === 'function'
? await PublicKeyCredential.isConditionalMediationAvailable()
: false;
if (!supported || cancelled)
return;
let startAuthentication;
try {
startAuthentication = await loadStartAuthentication();
}
catch {
return;
}
if (cancelled)
return;
const headers = {
'content-type': 'application/json',
};
if (csrfToken)
headers['x-csrf-token'] = csrfToken;
const optRes = await fetch(optionsUrl, {
method: 'POST',
headers,
body: JSON.stringify({}),
signal: ac.signal,
});
if (!optRes.ok || cancelled)
return;
const optionsJSON = await optRes.json();
optionsJSON._discoverable = undefined;
if (cancelled)
return;
const assertion = await startAuthentication({
optionsJSON,
useBrowserAutofill: true,
verifyBrowserAutofillInput: true,
}, ac.signal);
if (cancelled)
return;
onSuccess(JSON.stringify(assertion));
}
catch {
}
};
void run();
return () => {
cancelled = true;
ac.abort();
abortRef.current = null;
};
}, [enabled, optionsUrl, verifyUrl, onSuccess, csrfToken]);
}