UNPKG

@passkey-fas/webauthn-sdk

Version:

Official JavaScript SDK for FaS (FIDO2 as Service) Platform - Easy passwordless authentication integration

3 lines (2 loc) 5.76 kB
"use strict";var t=require("@simplewebauthn/browser");class e{constructor(t){if(!t.clientId&&!t.projectId)throw new Error("Either clientId or projectId is required");if(this.isPublicApi=!!t.projectId,this.isPublicApi)this.projectId=t.projectId,this.apiBase=t.apiBase||"/api/public",this.useProxy=!1,console.log("🌐 FaS SDK initialized in Public API mode");else{if(this.clientId=t.clientId,this.clientSecret=t.clientSecret,this.useProxy=t.useProxy||!1,this.apiBase=t.apiBase||"https://fas-l450.onrender.com/api/webauthn",!this.useProxy&&!this.clientSecret)throw new Error("clientSecret is required when not using proxy mode. Set useProxy: true to use backend proxy.");console.log("🔒 FaS SDK initialized in Private API mode")}this.timeout=t.timeout||6e4}async makeRequest(t,e={}){const i=new AbortController,r=setTimeout(()=>i.abort(),this.timeout);try{let o={"Content-Type":"application/json"};this.isPublicApi?(o["X-Project-ID"]=this.projectId,console.log("🌐 Public API request with Project ID:",this.projectId)):this.useProxy||(o["X-Client-ID"]=this.clientId,o["X-Client-Secret"]=this.clientSecret,console.log("🔒 Private API request with Client ID:",this.clientId));let n=`${this.apiBase}${t}`;if(this.isPublicApi){const e={"/public-register/start":"/register/start","/public-register/finish":"/register/finish","/public-authenticate/start":"/authenticate/start","/public-authenticate/finish":"/authenticate/finish"}[t];e&&(n=`${this.apiBase}${e}`)}else if(this.useProxy){const e={"/public-register/start":"/register/start","/public-register/finish":"/register/finish","/public-authenticate/start":"/authenticate/start","/public-authenticate/finish":"/authenticate/finish"}[t];e&&(n=`${this.apiBase}${e}`)}console.log("📡 Making request to:",n);const s=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(e),signal:i.signal});if(clearTimeout(r),!s.ok){const t=await s.json().catch(()=>({}));throw new Error(t.error||`HTTP ${s.status}: ${s.statusText}`)}return s.json()}catch(t){if(clearTimeout(r),"AbortError"===t.name)throw new Error("Request timeout");throw t}}async registerPasskey(e,i){if(!e)throw new Error("Email is required");try{console.log("🔑 Bắt đầu đăng ký passkey cho:",e);const r=await this.makeRequest("/public-register/start",{email:e,fullname:i||e});console.log("📋 Đã nhận tùy chọn đăng ký");const o=await t.startRegistration(r);console.log("✅ Hoàn tất đăng ký WebAuthn");const n=await this.makeRequest("/public-register/finish",{email:e,credential:o});return console.log("🎉 Xác minh đăng ký thành công"),n.token&&this.setAuthToken(n.token),{success:!0,user:n.user,token:n.token}}catch(t){throw console.error("❌ Đăng ký thất bại:",t),this.handleWebAuthnError(t)}}async authenticatePasskey(e){if(!e)throw new Error("Email is required");try{console.log("🔐 Starting passkey authentication for:",e);const i=await this.makeRequest("/public-authenticate/start",{email:e});console.log("📋 Authentication options received");const r=await t.startAuthentication(i);console.log("✅ WebAuthn authentication completed");const o=await this.makeRequest("/public-authenticate/finish",{email:e,credential:r});return console.log("🎉 Authentication verified successfully"),o.token&&this.setAuthToken(o.token),{success:!0,user:o.user,token:o.token}}catch(t){throw console.error("❌ Authentication failed:",t),this.handleWebAuthnError(t)}}async passwordlessLogin(){try{console.log("🚀 Starting passwordless authentication");const e=await this.makeRequest("/public-authenticate/start",{email:null});console.log("📋 Passwordless options received");const i=await t.startAuthentication(e);console.log("✅ Passwordless authentication completed");const r=await this.makeRequest("/public-authenticate/finish",{email:null,credential:i});return console.log("🎉 Passwordless authentication verified"),r.token&&this.setAuthToken(r.token),{success:!0,user:r.user,token:r.token}}catch(t){throw console.error("❌ Passwordless authentication failed:",t),this.handleWebAuthnError(t)}}getAuthToken(){return"undefined"!=typeof localStorage?localStorage.getItem("fas_auth_token"):null}setAuthToken(t){"undefined"!=typeof localStorage&&localStorage.setItem("fas_auth_token",t)}logout(){"undefined"!=typeof localStorage&&localStorage.removeItem("fas_auth_token")}isAuthenticated(){const t=this.getAuthToken();if(!t)return!1;try{return 1e3*JSON.parse(atob(t.split(".")[1])).exp>Date.now()}catch{return!1}}static isWebAuthnSupported(){return!!("undefined"!=typeof window&&window.navigator&&window.navigator.credentials&&window.navigator.credentials.create)}static getBrowserSupport(){const t={webauthn:e.isWebAuthnSupported(),conditionalUI:!1,residentKeys:!1,userVerification:!1};return t.webauthn&&"undefined"!=typeof window&&(t.conditionalUI=void 0!==window.PublicKeyCredential?.isConditionalMediationAvailable,t.residentKeys=!0,t.userVerification=!0),t}handleWebAuthnError(t){const e={NotAllowedError:"User cancelled the operation or timeout occurred",NotSupportedError:"WebAuthn is not supported on this device/browser",InvalidStateError:"A passkey already exists for this account on this device",SecurityError:"Security error - ensure you are using HTTPS",UnknownError:"An unknown error occurred during authentication",AbortError:"Operation was aborted by user or system",ConstraintError:"Constraint error occurred",NotReadableError:"Authenticator data is not readable",DataError:"Data provided is invalid"}[t.name]||t.message||"Unknown authentication error",i=new Error(e);return i.originalError=t,i.code=t.name||"UnknownError",i}}"undefined"!=typeof module&&module.exports&&(module.exports=e),"undefined"!=typeof window&&(window.FaSSDK=e),module.exports=e; //# sourceMappingURL=index.js.map