UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

3 lines (2 loc) 6.37 kB
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react"),B=require("./use-auth.cjs"),T=require("../provider/config-provider.cjs");function L(){return typeof window<"u"&&"navigator"in window&&"credentials"in navigator&&"create"in navigator.credentials&&"get"in navigator.credentials}async function j(){if(!L())return!1;try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return!1}}function b(r){const e=r.replace(/-/g,"+").replace(/_/g,"/"),n=e.padEnd(e.length+(4-e.length%4)%4,"="),l=atob(n),y=new ArrayBuffer(l.length),u=new Uint8Array(y);for(let c=0;c<l.length;c++)u[c]=l.charCodeAt(c);return y}function w(r){const e=new Uint8Array(r);let n="";for(let l=0;l<e.byteLength;l++)n+=String.fromCharCode(e[l]);return btoa(n).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}function H(r){return{...r,challenge:b(r.challenge),user:{...r.user,id:b(r.user.id)},excludeCredentials:r.excludeCredentials?.map(e=>({...e,id:b(e.id)}))}}function $(r){return{...r,challenge:b(r.challenge),allowCredentials:r.allowCredentials?.map(e=>({...e,id:b(e.id)}))}}function D(r){const e=r.response,n={id:r.id,rawId:w(r.rawId),type:r.type,response:{clientDataJSON:w(e.clientDataJSON)}};return e instanceof AuthenticatorAttestationResponse?n.response.attestationObject=w(e.attestationObject):e instanceof AuthenticatorAssertionResponse&&(n.response.authenticatorData=w(e.authenticatorData),n.response.signature=w(e.signature),e.userHandle&&(n.response.userHandle=w(e.userHandle))),n}function U(){const{user:r,sdk:e}=B.useAuth(),{apiUrl:n,publishableKey:l,features:y}=T.useConfig(),[u,c]=a.useState([]),[P,i]=a.useState(!1),[p,f]=a.useState(null),[N,O]=a.useState(!1),g=a.useMemo(()=>L(),[]),k=a.useMemo(()=>y.passkeys,[y.passkeys]),d=a.useCallback(t=>{const s={code:t.code||"UNKNOWN_ERROR",message:t.message||"An unknown error occurred",details:t.details,field:t.field};throw f(s),s},[]),C=a.useCallback(async()=>{if(!g)return!1;try{const t=await j();return O(t),t}catch{return O(!1),!1}},[g]),h=a.useCallback(async()=>{if(!(!e.user||!r||!k))try{i(!0),f(null);const t=await e.user.getPasskeys({fields:[]});c(t.data||[])}catch(t){console.error("Failed to load passkeys:",t),f({code:"PASSKEYS_LOAD_FAILED",message:"Failed to load passkeys"})}finally{i(!1)}},[e.user,r,k]);a.useEffect(()=>{C(),h()},[C,h]);const E=a.useCallback(async t=>{if(!e.user)throw new Error("User not authenticated");if(!g)throw new Error("WebAuthn not supported");if(!k)throw new Error("Passkeys not enabled");try{i(!0),f(null);const s=await e.auth.beginPasskeyRegistration({name:t||`Passkey ${u.length+1}`}),o=H(s.options);return{challenge:s.challenge,options:o,sessionId:s.sessionId}}catch(s){return d(s)}finally{i(!1)}},[e.auth,g,k,u.length,d]),S=a.useCallback(async(t,s)=>{if(!e.user)throw new Error("User not authenticated");try{i(!0),f(null);const o=D(s),I={sessionId:t.sessionId,credential:o},A=await e.auth.finishPasskeyRegistration(I);return await h(),A.passkey}catch(o){return d(o)}finally{i(!1)}},[e.user,h,d]),q=a.useCallback(async t=>{const s=await E(t);try{const o=await navigator.credentials.create({publicKey:s.options});if(!o)throw new Error("Failed to create credential");return await S(s,o)}catch(o){throw o.name==="NotAllowedError"?new Error("User cancelled the registration process"):o.name==="InvalidStateError"?new Error("This authenticator is already registered"):new Error(`Registration failed: ${o.message}`)}},[E,S]),m=a.useCallback(async()=>{if(!e.auth)throw new Error("User not authenticated");if(!g)throw new Error("WebAuthn not supported");try{i(!0),f(null);const t=await e.auth.beginPasskeyAuthentication({}),s=$(t.options);return{challenge:t.challenge,options:s,sessionId:t.sessionId}}catch(t){return d(t)}finally{i(!1)}},[e.auth,g,d]),v=a.useCallback(async(t,s)=>{if(!e.user)throw new Error("User not authenticated");try{i(!0),f(null);const o=D(s),I={sessionId:t.sessionId,credential:o},A=await e.auth.finishPasskeyAuthentication(I);return{success:!0,session:A.session,user:A.user}}catch(o){return{success:!1,error:o.message}}finally{i(!1)}},[e.auth,d]),K=a.useCallback(async()=>{const t=await m();try{const s=await navigator.credentials.get({publicKey:t.options});if(!s)throw new Error("Failed to get credential");return await v(t,s)}catch(s){return s.name==="NotAllowedError"?{success:!1,error:"User cancelled the authentication process"}:{success:!1,error:`Authentication failed: ${s.message}`}}},[m,v]),R=a.useCallback(async(t,s)=>{if(!e.user)throw new Error("User not authenticated");try{i(!0),f(null);const o=await e.user.updatePasskey(t,s);return await h(),o.passkey}catch(o){return d(o)}finally{i(!1)}},[e.user,h,d]),W=a.useCallback(async t=>{if(!e.user)throw new Error("User not authenticated");try{i(!0),f(null),await e.user.deletePasskey(t),await h()}catch(s){d(s)}finally{i(!1)}},[e.user,h,d]),F=a.useCallback(async(t,s)=>R(t,{name:s}),[R]),M=a.useCallback(async()=>{await h()},[h]),_=a.useMemo(()=>u.find(t=>t.isPrimary)||u[0]||null,[u]),z=a.useMemo(()=>u.length,[u]);return{passkeys:u,isSupported:g,isAvailable:N,isLoaded:!!r&&k,isLoading:P,error:p,beginRegistration:E,finishRegistration:S,registerPasskey:q,beginAuthentication:m,finishAuthentication:v,authenticateWithPasskey:K,updatePasskey:R,deletePasskey:W,renamePasskey:F,primaryPasskey:_,passkeyCount:z,refreshPasskeys:M,checkSupport:C}}function x(){const{registerPasskey:r,isSupported:e,isAvailable:n,isLoading:l,error:y}=U(),[u,c]=a.useState("idle");return{register:a.useCallback(async i=>{if(!e||!n)throw c("error"),new Error("Passkeys not supported or available");try{c("registering");const p=await r(i);return c("success"),p}catch(p){throw c("error"),p}},[r,e,n]),state:u,isSupported:e,isAvailable:n,isLoading:l,error:y,canRegister:e&&n&&!l}}function J(){const{authenticateWithPasskey:r,isSupported:e,isAvailable:n,isLoading:l,error:y}=U(),[u,c]=a.useState("idle");return{authenticate:a.useCallback(async()=>{if(!e||!n)throw c("error"),new Error("Passkeys not supported or available");try{c("authenticating");const i=await r();return i.success?c("success"):c("error"),i}catch(i){throw c("error"),i}},[r,e,n]),state:u,isSupported:e,isAvailable:n,isLoading:l,error:y,canAuthenticate:e&&n&&!l}}exports.usePasskeyAuthentication=J;exports.usePasskeyRegistration=x;exports.usePasskeys=U; //# sourceMappingURL=use-passkeys.cjs.map