Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@passwordless-id/webauthn

Package Overview
Dependencies
Maintainers
1
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@passwordless-id/webauthn - npm Package Compare versions

Comparing version 1.2.4 to 1.2.5

1

dist/esm/client.d.ts

@@ -35,3 +35,4 @@ import { AuthenticateOptions, AuthenticationEncoded, RegisterOptions, RegistrationEncoded } from './types.js';

* @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not.
* @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
*/
export declare function authenticate(credentialIds: string[], challenge: string, options?: AuthenticateOptions): Promise<AuthenticationEncoded>;

5

dist/esm/client.js

@@ -69,3 +69,3 @@ import * as utils from './utils.js';

user: {
id: await utils.sha256(new TextEncoder().encode(username)),
id: await utils.sha256(new TextEncoder().encode('passwordless.id-user:' + username)),
name: username,

@@ -136,2 +136,3 @@ displayName: username,

* @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not.
* @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
*/

@@ -158,3 +159,3 @@ export async function authenticate(credentialIds, challenge, options) {

console.debug(authOptions);
let auth = await navigator.credentials.get({ publicKey: authOptions });
let auth = await navigator.credentials.get({ publicKey: authOptions, mediation: options.mediation });
if (options.debug)

@@ -161,0 +162,0 @@ console.debug(auth);

@@ -9,2 +9,3 @@ export type AuthType = 'auto' | 'local' | 'extern' | 'roaming' | 'both';

debug?: boolean;
mediation?: CredentialMediationRequirement;
}

@@ -11,0 +12,0 @@ export interface AuthenticationEncoded {

@@ -1,2 +0,2 @@

var N=Object.defineProperty;var f=(e,t)=>{for(var a in t)N(e,a,{get:t[a],enumerable:!0})};var w={};f(w,{authenticate:()=>Y,isAvailable:()=>H,isLocalAuthenticator:()=>A,register:()=>v});var u={};f(u,{bufferToHex:()=>y,concatenateBuffers:()=>h,isBase64url:()=>m,parseBase64url:()=>s,parseBuffer:()=>O,randomChallenge:()=>T,sha256:()=>l,toBase64url:()=>c,toBuffer:()=>b});function T(){return crypto.randomUUID()}function b(e){return Uint8Array.from(e,t=>t.charCodeAt(0)).buffer}function O(e){return String.fromCharCode(...new Uint8Array(e))}function m(e){return e.match(/^[a-zA-Z0-9\-_]+=*$/)!==null}function c(e){return btoa(O(e)).replaceAll("+","-").replaceAll("/","_")}function s(e){return e=e.replaceAll("-","+").replaceAll("_","/"),b(atob(e))}async function l(e){return await crypto.subtle.digest("SHA-256",e)}function y(e){return[...new Uint8Array(e)].map(t=>t.toString(16).padStart(2,"0")).join("")}function h(e,t){var a=new Uint8Array(e.byteLength+t.byteLength);return a.set(new Uint8Array(e),0),a.set(new Uint8Array(t),e.byteLength),a}function H(){return!!window.PublicKeyCredential}async function A(){return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}async function R(e){if(e==="local")return"platform";if(e==="roaming"||e==="extern")return"cross-platform";if(e!=="both")try{return await A()?"platform":"cross-platform"}catch{return}}function V(e){switch(e){case-7:return"ES256";case-257:return"RS256";default:throw new Error(`Unknown algorithm code: ${e}`)}}async function v(e,t,a){if(a=a??{},!m(t))throw new Error("Provided challenge is not properly encoded in Base64url");let n={challenge:s(t),rp:{id:window.location.hostname,name:window.location.hostname},user:{id:await l(new TextEncoder().encode(e)),name:e,displayName:e},pubKeyCredParams:[{alg:-7,type:"public-key"},{alg:-257,type:"public-key"}],timeout:a.timeout??6e4,authenticatorSelection:{userVerification:a.userVerification??"required",authenticatorAttachment:await R(a.authenticatorType??"auto")},attestation:"direct"};a.debug&&console.debug(n);let r=await navigator.credentials.create({publicKey:n});a.debug&&console.debug(r);let i=r.response,o={username:e,credential:{id:r.id,publicKey:c(i.getPublicKey()),algorithm:V(r.response.getPublicKeyAlgorithm())},authenticatorData:c(i.getAuthenticatorData()),clientData:c(i.clientDataJSON)};return a.attestation&&(o.attestationData=c(i.attestationObject)),o}async function k(e){let t=["internal"],a=["hybrid","usb","ble","nfc"];if(e==="local")return t;if(e=="roaming"||e==="extern")return a;if(e==="both")return[...t,...a];try{return await A()?t:a}catch{return[...t,...a]}}async function Y(e,t,a){if(a=a??{},!m(t))throw new Error("Provided challenge is not properly encoded in Base64url");let n=await k(a.authenticatorType??"auto"),r={challenge:s(t),rpId:window.location.hostname,allowCredentials:e.map(d=>({id:s(d),type:"public-key",transports:n})),userVerification:a.userVerification??"required",timeout:a.timeout??6e4};a.debug&&console.debug(r);let i=await navigator.credentials.get({publicKey:r});a.debug&&console.debug(i);let o=i.response;return{credentialId:i.id,authenticatorData:c(o.authenticatorData),clientData:c(o.clientDataJSON),signature:c(o.signature)}}var I={};f(I,{verifyAuthentication:()=>q,verifyRegistration:()=>j,verifySignature:()=>U});var B={};f(B,{parseAttestation:()=>x,parseAuthentication:()=>D,parseAuthenticator:()=>C,parseClient:()=>P,parseRegistration:()=>S});var F={"9c835346-796b-4c27-8898-d6032f515cc5":{name:"Cryptnox FIDO2"},"c5ef55ff-ad9a-4b9f-b580-adebafe026d0":{name:"YubiKey 5Ci"},"39a5647e-1853-446c-a1f6-a79bae9f5bc7":{name:"Vancosys Android Authenticator"},"3789da91-f943-46bc-95c3-50ea2012f03a":{name:"NEOWAVE Winkeo FIDO2"},"fa2b99dc-9e39-4257-8f92-4a30d23c4118":{name:"YubiKey 5 Series with NFC"},"4e768f2c-5fab-48b3-b300-220eb487752b":{name:"Hideez Key 4 FIDO2 SDK"},"931327dd-c89b-406c-a81e-ed7058ef36c6":{name:"Swissbit iShield FIDO2"},"e1a96183-5016-4f24-b55b-e3ae23614cc6":{name:"ATKey.Pro CTAP2.0"},"08987058-cadc-4b81-b6e1-30de50dcbe96":{name:"Windows Hello Hardware Authenticator"},"d91c5288-0ef0-49b7-b8ae-21ca0aa6b3f3":{name:"KEY-ID FIDO2 Authenticator"},"ee041bce-25e5-4cdb-8f86-897fd6418464":{name:"Feitian ePass FIDO2-NFC Authenticator"},"73bb0cd4-e502-49b8-9c6f-b59445bf720b":{name:"YubiKey 5 FIPS Series"},"149a2021-8ef6-4133-96b8-81f8d5b7f1f5":{name:"Security Key by Yubico with NFC"},"3b1adb99-0dfe-46fd-90b8-7f7614a4de2a":{name:"GoTrust Idem Key FIDO2 Authenticator"},"f8a011f3-8c0a-4d15-8006-17111f9edc7d":{name:"Security Key by Yubico"},"2c0df832-92de-4be1-8412-88a8f074df4a":{name:"Feitian FIDO Smart Card"},"c5703116-972b-4851-a3e7-ae1259843399":{name:"NEOWAVE Badgeo FIDO2"},"820d89ed-d65a-409e-85cb-f73f0578f82a":{name:"Vancosys iOS Authenticator"},"b6ede29c-3772-412c-8a78-539c1f4c62d2":{name:"Feitian BioPass FIDO2 Plus Authenticator"},"85203421-48f9-4355-9bc8-8a53846e5083":{name:"YubiKey 5Ci FIPS"},"d821a7d4-e97c-4cb6-bd82-4237731fd4be":{name:"Hyper FIDO Bio Security Key"},"516d3969-5a57-5651-5958-4e7a49434167":{name:"SmartDisplayer BobeePass (NFC-BLE FIDO2 Authenticator)"},"b93fd961-f2e6-462f-b122-82002247de78":{name:"Android Authenticator with SafetyNet Attestation"},"2fc0579f-8113-47ea-b116-bb5a8db9202a":{name:"YubiKey 5 Series with NFC"},"9ddd1817-af5a-4672-a2b9-3e3dd95000a9":{name:"Windows Hello VBS Hardware Authenticator"},"d8522d9f-575b-4866-88a9-ba99fa02f35b":{name:"YubiKey Bio Series"},"692db549-7ae5-44d5-a1e5-dd20a493b723":{name:"HID Crescendo Key"},"3e22415d-7fdf-4ea4-8a0c-dd60c4249b9d":{name:"Feitian iePass FIDO Authenticator"},"aeb6569c-f8fb-4950-ac60-24ca2bbe2e52":{name:"HID Crescendo C2300"},"9f0d8150-baa5-4c00-9299-ad62c8bb4e87":{name:"GoTrust Idem Card FIDO2 Authenticator"},"12ded745-4bed-47d4-abaa-e713f51d6393":{name:"Feitian AllinOne FIDO2 Authenticator"},"88bbd2f0-342a-42e7-9729-dd158be5407a":{name:"Precision InnaIT Key FIDO 2 Level 2 certified"},"34f5766d-1536-4a24-9033-0e294e510fb0":{name:"YubiKey 5 Series CTAP2.1 Preview 1 "},"83c47309-aabb-4108-8470-8be838b573cb":{name:"YubiKey Bio Series (Enterprise Profile)"},"be727034-574a-f799-5c76-0929e0430973":{name:"Crayonic KeyVault K1 (USB-NFC-BLE FIDO2 Authenticator)"},"b92c3f9a-c014-4056-887f-140a2501163b":{name:"Security Key by Yubico"},"54d9fee8-e621-4291-8b18-7157b99c5bec":{name:"HID Crescendo Enabled"},"6028b017-b1d4-4c02-b4b3-afcdafc96bb2":{name:"Windows Hello Software Authenticator"},"6d44ba9b-f6ec-2e49-b930-0c8fe920cb73":{name:"Security Key by Yubico with NFC"},"e416201b-afeb-41ca-a03d-2281c28322aa":{name:"ATKey.Pro CTAP2.1"},"9f77e279-a6e2-4d58-b700-31e5943c6a98":{name:"Hyper FIDO Pro"},"73402251-f2a8-4f03-873e-3cb6db604b03":{name:"uTrust FIDO2 Security Key"},"c1f9a0bc-1dd2-404a-b27f-8e29047a43fd":{name:"YubiKey 5 FIPS Series with NFC"},"504d7149-4e4c-3841-4555-55445a677357":{name:"WiSECURE AuthTron USB FIDO2 Authenticator"},"cb69481e-8ff7-4039-93ec-0a2729a154a8":{name:"YubiKey 5 Series"},"ee882879-721c-4913-9775-3dfcce97072a":{name:"YubiKey 5 Series"},"8c97a730-3f7b-41a6-87d6-1e9b62bda6f0":{name:"FT-JCOS FIDO Fingerprint Card"},"a1f52be5-dfab-4364-b51c-2bd496b14a56":{name:"OCTATCO EzFinger2 FIDO2 AUTHENTICATOR"},"3e078ffd-4c54-4586-8baa-a77da113aec5":{name:"Hideez Key 3 FIDO2"},"d41f5a69-b817-4144-a13c-9ebd6d9254d6":{name:"ATKey.Card CTAP2.0"},"bc2fe499-0d8e-4ffe-96f3-94a82840cf8c":{name:"OCTATCO EzQuant FIDO2 AUTHENTICATOR"},"1c086528-58d5-f211-823c-356786e36140":{name:"Atos CardOS FIDO2"},"77010bd7-212a-4fc9-b236-d2ca5e9d4084":{name:"Feitian BioPass FIDO2 Authenticator"},"833b721a-ff5f-4d00-bb2e-bdda3ec01e29":{name:"Feitian ePass FIDO2 Authenticator"}};function K(e){console.debug(e);let t=new DataView(e.slice(32,33)).getUint8(0);console.debug(t);let a={rpIdHash:c(e.slice(0,32)),flags:{userPresent:!!(t&1),userVerified:!!(t&4),backupEligibility:!!(t&8),backupState:!!(t&16),attestedData:!!(t&64),extensionsIncluded:!!(t&128)},counter:new DataView(e.slice(33,37)).getUint32(0,!1)};if(e.byteLength>37){let n=$(e);a={...a,aaguid:n,name:W(n)}}return a}function $(e){return L(e.slice(37,53))}function L(e){let t=y(e);return t=t.substring(0,8)+"-"+t.substring(8,12)+"-"+t.substring(12,16)+"-"+t.substring(16,20)+"-"+t.substring(20,32),t}function W(e){return(J??F)[e]?.name}var J=null;var z=new TextDecoder("utf-8");function P(e){return typeof e=="string"&&(e=s(e)),JSON.parse(z.decode(e))}function C(e){return typeof e=="string"&&(e=s(e)),K(e)}function x(e){return typeof e=="string"&&(e=s(e)),"Really complex to parse. Good luck with that one!"}function S(e){return{username:e.username,credential:e.credential,client:P(e.clientData),authenticator:C(e.authenticatorData),attestation:e.attestationData?x(e.attestationData):null}}function D(e){return{credentialId:e.credentialId,client:P(e.clientData),authenticator:C(e.authenticatorData),signature:e.signature}}async function _(e,t){if(typeof e=="function"){let a=e(t);return a instanceof Promise?await a:a}return e===t}async function g(e,t){return!await _(e,t)}async function j(e,t){let a=S(e);if(a.client.challenge,a.client.type!=="webauthn.create")throw new Error(`Unexpected ClientData type: ${a.client.type}`);if(await g(t.origin,a.client.origin))throw new Error(`Unexpected ClientData origin: ${a.client.origin}`);if(await g(t.challenge,a.client.challenge))throw new Error(`Unexpected ClientData challenge: ${a.client.challenge}`);return a}async function q(e,t,a){if(e.credentialId!==t.id)throw new Error(`Credential ID mismatch: ${e.credentialId} vs ${t.id}`);if(!await U({algorithm:t.algorithm,publicKey:t.publicKey,authenticatorData:e.authenticatorData,clientData:e.clientData,signature:e.signature}))throw new Error(`Invalid signature: ${e.signature}`);let r=D(e);if(r.client.type!=="webauthn.get")throw new Error(`Unexpected clientData type: ${r.client.type}`);if(await g(a.origin,r.client.origin))throw new Error(`Unexpected ClientData origin: ${r.client.origin}`);if(await g(a.challenge,r.client.challenge))throw new Error(`Unexpected ClientData challenge: ${r.client.challenge}`);let i=new URL(r.client.origin).hostname,o=c(await l(b(i)));if(r.authenticator.rpIdHash!==o)throw new Error(`Unexpected RpIdHash: ${r.authenticator.rpIdHash} vs ${o}`);if(!r.authenticator.flags.userPresent)throw new Error("Unexpected authenticator flags: missing userPresent");if(!r.authenticator.flags.userVerified&&a.userVerified)throw new Error("Unexpected authenticator flags: missing userVerified");if(r.authenticator.counter<=a.counter)throw new Error(`Unexpected authenticator counter: ${r.authenticator.counter} (should be > ${a.counter})`);return r}function G(e){switch(e){case"RS256":return{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"};case"ES256":return{name:"ECDSA",namedCurve:"P-256",hash:"SHA-256"};default:throw new Error(`Unknown or unsupported crypto algorithm: ${e}. Only 'RS256' and 'ES256' are supported.`)}}async function Q(e,t){let a=s(t);return crypto.subtle.importKey("spki",a,e,!1,["verify"])}async function U({algorithm:e,publicKey:t,authenticatorData:a,clientData:n,signature:r}){let i=G(e),o=await Q(i,t);console.debug(o);let E=await l(s(n)),d=h(s(a),E);console.debug("Crypto Algo: "+JSON.stringify(i)),console.debug("Public key: "+t),console.debug("Data: "+c(d)),console.debug("Signature: "+r);let p=s(r);return e=="ES256"&&(p=Z(p)),await crypto.subtle.verify(i,o,p,d)}function Z(e){let t=new Uint8Array(e),a=t[4]===0?5:4,n=a+32,r=t[n+2]===0?n+3:n+2,i=t.slice(a,n),o=t.slice(r);return new Uint8Array([...i,...o])}var ne={client:w,server:I,parsers:B,utils:u};export{w as client,ne as default,B as parsers,I as server,u as utils};
var N=Object.defineProperty;var f=(e,t)=>{for(var a in t)N(e,a,{get:t[a],enumerable:!0})};var w={};f(w,{authenticate:()=>Y,isAvailable:()=>H,isLocalAuthenticator:()=>A,register:()=>v});var u={};f(u,{bufferToHex:()=>y,concatenateBuffers:()=>h,isBase64url:()=>m,parseBase64url:()=>c,parseBuffer:()=>O,randomChallenge:()=>T,sha256:()=>l,toBase64url:()=>s,toBuffer:()=>b});function T(){return crypto.randomUUID()}function b(e){return Uint8Array.from(e,t=>t.charCodeAt(0)).buffer}function O(e){return String.fromCharCode(...new Uint8Array(e))}function m(e){return e.match(/^[a-zA-Z0-9\-_]+=*$/)!==null}function s(e){return btoa(O(e)).replaceAll("+","-").replaceAll("/","_")}function c(e){return e=e.replaceAll("-","+").replaceAll("_","/"),b(atob(e))}async function l(e){return await crypto.subtle.digest("SHA-256",e)}function y(e){return[...new Uint8Array(e)].map(t=>t.toString(16).padStart(2,"0")).join("")}function h(e,t){var a=new Uint8Array(e.byteLength+t.byteLength);return a.set(new Uint8Array(e),0),a.set(new Uint8Array(t),e.byteLength),a}function H(){return!!window.PublicKeyCredential}async function A(){return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}async function R(e){if(e==="local")return"platform";if(e==="roaming"||e==="extern")return"cross-platform";if(e!=="both")try{return await A()?"platform":"cross-platform"}catch{return}}function V(e){switch(e){case-7:return"ES256";case-257:return"RS256";default:throw new Error(`Unknown algorithm code: ${e}`)}}async function v(e,t,a){if(a=a??{},!m(t))throw new Error("Provided challenge is not properly encoded in Base64url");let n={challenge:c(t),rp:{id:window.location.hostname,name:window.location.hostname},user:{id:await l(new TextEncoder().encode("passwordless.id-user:"+e)),name:e,displayName:e},pubKeyCredParams:[{alg:-7,type:"public-key"},{alg:-257,type:"public-key"}],timeout:a.timeout??6e4,authenticatorSelection:{userVerification:a.userVerification??"required",authenticatorAttachment:await R(a.authenticatorType??"auto")},attestation:"direct"};a.debug&&console.debug(n);let r=await navigator.credentials.create({publicKey:n});a.debug&&console.debug(r);let i=r.response,o={username:e,credential:{id:r.id,publicKey:s(i.getPublicKey()),algorithm:V(r.response.getPublicKeyAlgorithm())},authenticatorData:s(i.getAuthenticatorData()),clientData:s(i.clientDataJSON)};return a.attestation&&(o.attestationData=s(i.attestationObject)),o}async function k(e){let t=["internal"],a=["hybrid","usb","ble","nfc"];if(e==="local")return t;if(e=="roaming"||e==="extern")return a;if(e==="both")return[...t,...a];try{return await A()?t:a}catch{return[...t,...a]}}async function Y(e,t,a){if(a=a??{},!m(t))throw new Error("Provided challenge is not properly encoded in Base64url");let n=await k(a.authenticatorType??"auto"),r={challenge:c(t),rpId:window.location.hostname,allowCredentials:e.map(d=>({id:c(d),type:"public-key",transports:n})),userVerification:a.userVerification??"required",timeout:a.timeout??6e4};a.debug&&console.debug(r);let i=await navigator.credentials.get({publicKey:r,mediation:a.mediation});a.debug&&console.debug(i);let o=i.response;return{credentialId:i.id,authenticatorData:s(o.authenticatorData),clientData:s(o.clientDataJSON),signature:s(o.signature)}}var I={};f(I,{verifyAuthentication:()=>q,verifyRegistration:()=>j,verifySignature:()=>U});var B={};f(B,{parseAttestation:()=>x,parseAuthentication:()=>D,parseAuthenticator:()=>C,parseClient:()=>P,parseRegistration:()=>S});var F={"9c835346-796b-4c27-8898-d6032f515cc5":{name:"Cryptnox FIDO2"},"c5ef55ff-ad9a-4b9f-b580-adebafe026d0":{name:"YubiKey 5Ci"},"39a5647e-1853-446c-a1f6-a79bae9f5bc7":{name:"Vancosys Android Authenticator"},"3789da91-f943-46bc-95c3-50ea2012f03a":{name:"NEOWAVE Winkeo FIDO2"},"fa2b99dc-9e39-4257-8f92-4a30d23c4118":{name:"YubiKey 5 Series with NFC"},"4e768f2c-5fab-48b3-b300-220eb487752b":{name:"Hideez Key 4 FIDO2 SDK"},"931327dd-c89b-406c-a81e-ed7058ef36c6":{name:"Swissbit iShield FIDO2"},"e1a96183-5016-4f24-b55b-e3ae23614cc6":{name:"ATKey.Pro CTAP2.0"},"08987058-cadc-4b81-b6e1-30de50dcbe96":{name:"Windows Hello Hardware Authenticator"},"d91c5288-0ef0-49b7-b8ae-21ca0aa6b3f3":{name:"KEY-ID FIDO2 Authenticator"},"ee041bce-25e5-4cdb-8f86-897fd6418464":{name:"Feitian ePass FIDO2-NFC Authenticator"},"73bb0cd4-e502-49b8-9c6f-b59445bf720b":{name:"YubiKey 5 FIPS Series"},"149a2021-8ef6-4133-96b8-81f8d5b7f1f5":{name:"Security Key by Yubico with NFC"},"3b1adb99-0dfe-46fd-90b8-7f7614a4de2a":{name:"GoTrust Idem Key FIDO2 Authenticator"},"f8a011f3-8c0a-4d15-8006-17111f9edc7d":{name:"Security Key by Yubico"},"2c0df832-92de-4be1-8412-88a8f074df4a":{name:"Feitian FIDO Smart Card"},"c5703116-972b-4851-a3e7-ae1259843399":{name:"NEOWAVE Badgeo FIDO2"},"820d89ed-d65a-409e-85cb-f73f0578f82a":{name:"Vancosys iOS Authenticator"},"b6ede29c-3772-412c-8a78-539c1f4c62d2":{name:"Feitian BioPass FIDO2 Plus Authenticator"},"85203421-48f9-4355-9bc8-8a53846e5083":{name:"YubiKey 5Ci FIPS"},"d821a7d4-e97c-4cb6-bd82-4237731fd4be":{name:"Hyper FIDO Bio Security Key"},"516d3969-5a57-5651-5958-4e7a49434167":{name:"SmartDisplayer BobeePass (NFC-BLE FIDO2 Authenticator)"},"b93fd961-f2e6-462f-b122-82002247de78":{name:"Android Authenticator with SafetyNet Attestation"},"2fc0579f-8113-47ea-b116-bb5a8db9202a":{name:"YubiKey 5 Series with NFC"},"9ddd1817-af5a-4672-a2b9-3e3dd95000a9":{name:"Windows Hello VBS Hardware Authenticator"},"d8522d9f-575b-4866-88a9-ba99fa02f35b":{name:"YubiKey Bio Series"},"692db549-7ae5-44d5-a1e5-dd20a493b723":{name:"HID Crescendo Key"},"3e22415d-7fdf-4ea4-8a0c-dd60c4249b9d":{name:"Feitian iePass FIDO Authenticator"},"aeb6569c-f8fb-4950-ac60-24ca2bbe2e52":{name:"HID Crescendo C2300"},"9f0d8150-baa5-4c00-9299-ad62c8bb4e87":{name:"GoTrust Idem Card FIDO2 Authenticator"},"12ded745-4bed-47d4-abaa-e713f51d6393":{name:"Feitian AllinOne FIDO2 Authenticator"},"88bbd2f0-342a-42e7-9729-dd158be5407a":{name:"Precision InnaIT Key FIDO 2 Level 2 certified"},"34f5766d-1536-4a24-9033-0e294e510fb0":{name:"YubiKey 5 Series CTAP2.1 Preview 1 "},"83c47309-aabb-4108-8470-8be838b573cb":{name:"YubiKey Bio Series (Enterprise Profile)"},"be727034-574a-f799-5c76-0929e0430973":{name:"Crayonic KeyVault K1 (USB-NFC-BLE FIDO2 Authenticator)"},"b92c3f9a-c014-4056-887f-140a2501163b":{name:"Security Key by Yubico"},"54d9fee8-e621-4291-8b18-7157b99c5bec":{name:"HID Crescendo Enabled"},"6028b017-b1d4-4c02-b4b3-afcdafc96bb2":{name:"Windows Hello Software Authenticator"},"6d44ba9b-f6ec-2e49-b930-0c8fe920cb73":{name:"Security Key by Yubico with NFC"},"e416201b-afeb-41ca-a03d-2281c28322aa":{name:"ATKey.Pro CTAP2.1"},"9f77e279-a6e2-4d58-b700-31e5943c6a98":{name:"Hyper FIDO Pro"},"73402251-f2a8-4f03-873e-3cb6db604b03":{name:"uTrust FIDO2 Security Key"},"c1f9a0bc-1dd2-404a-b27f-8e29047a43fd":{name:"YubiKey 5 FIPS Series with NFC"},"504d7149-4e4c-3841-4555-55445a677357":{name:"WiSECURE AuthTron USB FIDO2 Authenticator"},"cb69481e-8ff7-4039-93ec-0a2729a154a8":{name:"YubiKey 5 Series"},"ee882879-721c-4913-9775-3dfcce97072a":{name:"YubiKey 5 Series"},"8c97a730-3f7b-41a6-87d6-1e9b62bda6f0":{name:"FT-JCOS FIDO Fingerprint Card"},"a1f52be5-dfab-4364-b51c-2bd496b14a56":{name:"OCTATCO EzFinger2 FIDO2 AUTHENTICATOR"},"3e078ffd-4c54-4586-8baa-a77da113aec5":{name:"Hideez Key 3 FIDO2"},"d41f5a69-b817-4144-a13c-9ebd6d9254d6":{name:"ATKey.Card CTAP2.0"},"bc2fe499-0d8e-4ffe-96f3-94a82840cf8c":{name:"OCTATCO EzQuant FIDO2 AUTHENTICATOR"},"1c086528-58d5-f211-823c-356786e36140":{name:"Atos CardOS FIDO2"},"77010bd7-212a-4fc9-b236-d2ca5e9d4084":{name:"Feitian BioPass FIDO2 Authenticator"},"833b721a-ff5f-4d00-bb2e-bdda3ec01e29":{name:"Feitian ePass FIDO2 Authenticator"}};function K(e){console.debug(e);let t=new DataView(e.slice(32,33)).getUint8(0);console.debug(t);let a={rpIdHash:s(e.slice(0,32)),flags:{userPresent:!!(t&1),userVerified:!!(t&4),backupEligibility:!!(t&8),backupState:!!(t&16),attestedData:!!(t&64),extensionsIncluded:!!(t&128)},counter:new DataView(e.slice(33,37)).getUint32(0,!1)};if(e.byteLength>37){let n=$(e);a={...a,aaguid:n,name:W(n)}}return a}function $(e){return L(e.slice(37,53))}function L(e){let t=y(e);return t=t.substring(0,8)+"-"+t.substring(8,12)+"-"+t.substring(12,16)+"-"+t.substring(16,20)+"-"+t.substring(20,32),t}function W(e){return(J??F)[e]?.name}var J=null;var z=new TextDecoder("utf-8");function P(e){return typeof e=="string"&&(e=c(e)),JSON.parse(z.decode(e))}function C(e){return typeof e=="string"&&(e=c(e)),K(e)}function x(e){return typeof e=="string"&&(e=c(e)),"Really complex to parse. Good luck with that one!"}function S(e){return{username:e.username,credential:e.credential,client:P(e.clientData),authenticator:C(e.authenticatorData),attestation:e.attestationData?x(e.attestationData):null}}function D(e){return{credentialId:e.credentialId,client:P(e.clientData),authenticator:C(e.authenticatorData),signature:e.signature}}async function _(e,t){if(typeof e=="function"){let a=e(t);return a instanceof Promise?await a:a}return e===t}async function g(e,t){return!await _(e,t)}async function j(e,t){let a=S(e);if(a.client.challenge,a.client.type!=="webauthn.create")throw new Error(`Unexpected ClientData type: ${a.client.type}`);if(await g(t.origin,a.client.origin))throw new Error(`Unexpected ClientData origin: ${a.client.origin}`);if(await g(t.challenge,a.client.challenge))throw new Error(`Unexpected ClientData challenge: ${a.client.challenge}`);return a}async function q(e,t,a){if(e.credentialId!==t.id)throw new Error(`Credential ID mismatch: ${e.credentialId} vs ${t.id}`);if(!await U({algorithm:t.algorithm,publicKey:t.publicKey,authenticatorData:e.authenticatorData,clientData:e.clientData,signature:e.signature}))throw new Error(`Invalid signature: ${e.signature}`);let r=D(e);if(r.client.type!=="webauthn.get")throw new Error(`Unexpected clientData type: ${r.client.type}`);if(await g(a.origin,r.client.origin))throw new Error(`Unexpected ClientData origin: ${r.client.origin}`);if(await g(a.challenge,r.client.challenge))throw new Error(`Unexpected ClientData challenge: ${r.client.challenge}`);let i=new URL(r.client.origin).hostname,o=s(await l(b(i)));if(r.authenticator.rpIdHash!==o)throw new Error(`Unexpected RpIdHash: ${r.authenticator.rpIdHash} vs ${o}`);if(!r.authenticator.flags.userPresent)throw new Error("Unexpected authenticator flags: missing userPresent");if(!r.authenticator.flags.userVerified&&a.userVerified)throw new Error("Unexpected authenticator flags: missing userVerified");if(r.authenticator.counter<=a.counter)throw new Error(`Unexpected authenticator counter: ${r.authenticator.counter} (should be > ${a.counter})`);return r}function G(e){switch(e){case"RS256":return{name:"RSASSA-PKCS1-v1_5",hash:"SHA-256"};case"ES256":return{name:"ECDSA",namedCurve:"P-256",hash:"SHA-256"};default:throw new Error(`Unknown or unsupported crypto algorithm: ${e}. Only 'RS256' and 'ES256' are supported.`)}}async function Q(e,t){let a=c(t);return crypto.subtle.importKey("spki",a,e,!1,["verify"])}async function U({algorithm:e,publicKey:t,authenticatorData:a,clientData:n,signature:r}){let i=G(e),o=await Q(i,t);console.debug(o);let E=await l(c(n)),d=h(c(a),E);console.debug("Crypto Algo: "+JSON.stringify(i)),console.debug("Public key: "+t),console.debug("Data: "+s(d)),console.debug("Signature: "+r);let p=c(r);return e=="ES256"&&(p=Z(p)),await crypto.subtle.verify(i,o,p,d)}function Z(e){let t=new Uint8Array(e),a=t[4]===0?5:4,n=a+32,r=t[n+2]===0?n+3:n+2,i=t.slice(a,n),o=t.slice(r);return new Uint8Array([...i,...o])}var ne={client:w,server:I,parsers:B,utils:u};export{w as client,ne as default,B as parsers,I as server,u as utils};
//# sourceMappingURL=webauthn.min.js.map
{
"name": "@passwordless-id/webauthn",
"version": "1.2.4",
"version": "1.2.5",
"description": "A small wrapper around the webauthn protocol to make one's life easier.",

@@ -5,0 +5,0 @@ "type": "module",

@@ -5,2 +5,3 @@ Passwordless.ID / webauthn

A greatly simplified and opinionated wrapper to invoke the [webauthn protocol](https://w3c.github.io/webauthn/) more conveniently.
It is minimalistik (11kb) and dependency-free.

@@ -15,4 +16,6 @@ <img src="demos/img/banner-biometric-auth.svg" />

Or the demos with minial examples:
---
Other demos with minial examples:
- [Basic Demo](https://webauthn.passwordless.id/demos/basic.html)

@@ -22,2 +25,3 @@ - [Minimal Example (CDN)](https://webauthn.passwordless.id/demos/example-cdn.html)

GitHub: https://github.com/passwordless-id/webauthn

@@ -53,3 +57,3 @@

<script type="module">
import { client } from 'https://unpkg.com/@passwordless-id/webauthn'
import { client } from 'https://unpkg.com/@passwordless-id/webauthn@1.2.5/dist/webauthn.min.js'
</script>

@@ -252,3 +256,3 @@ ```

```js
import { client } from 'webauthn'
import { client } from '@passwordless-id/webauthn'

@@ -296,6 +300,9 @@ const challenge = "56535b13-5d93-4194-a282-f234c1c24500"

userVerified: true, // should be set if `userVerification` was set to `required` in the authentication options (default)
counter: 0 // for enhanced security, you can store the number of times this authenticator was used and ensure it increases each time
counter: 0 // for better security, you should verify the authenticator "usage" counter increased since last time
}
```
> On iOS/MacOS, the `counter` value for the first authentication will be 0, while on Android/Windows the `counter` will start with 1.
> So using a counter value of `-1` seems best to cover the initial case. Please note that the specs do not mandate "+1" increases, it could theoretically increase by any amount.
Often, it might also be more practical to use functions to verify challenge or origin. This is possible too:

@@ -374,5 +381,5 @@

- `debug`: If enabled, parses the "data" objects and provide it in a "debug" properties.
- `mediation`: (Only for authentication) See https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
Parsing data

@@ -379,0 +386,0 @@ ------------

@@ -84,3 +84,3 @@ import * as utils from './utils.js'

user: {
id: await utils.sha256(new TextEncoder().encode(username)), // ID should not be directly "identifiable" for privacy concerns
id: await utils.sha256(new TextEncoder().encode('passwordless.id-user:' + username)), // ID should not be directly "identifiable" for privacy concerns
name: username,

@@ -164,2 +164,3 @@ displayName: username,

* @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not.
* @param {'optional'|'conditional'|'required'|'silent'} [options.mediation='optional'] https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
*/

@@ -189,3 +190,3 @@ export async function authenticate(credentialIds :string[], challenge :string, options? :AuthenticateOptions) :Promise<AuthenticationEncoded> {

let auth = await navigator.credentials.get({publicKey: authOptions}) as PublicKeyCredential
let auth = await navigator.credentials.get({publicKey: authOptions, mediation: options.mediation}) as PublicKeyCredential

@@ -192,0 +193,0 @@ if(options.debug)

@@ -16,2 +16,3 @@ // 'extern' is deprecated in favor of 'roaming' but kept for compatibility purposes

debug ?:boolean
mediation ?:CredentialMediationRequirement;
}

@@ -18,0 +19,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc