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 0.0.4 to 0.0.5

demos/basic.html

17

package.json
{
"name": "@passwordless-id/webauthn",
"version": "0.0.4",
"description": "A small wrapper around the webauthn protocol to make one's life easier.",
"main": "src/passwordless.ts",
"version": "0.0.5",
"description": "A small wrapper around the webauthn protocol to make one's life easier.",
"main": "src/webauthn.ts",
"scripts": {
"build": "esbuild src/passwordless.ts --platform=neutral --bundle --sourcemap --minify --target=es2022 --outfile=dist/passwordless.min.js"
"build": "esbuild src/webauthn.ts --platform=neutral --bundle --sourcemap --minify --target=es2022 --outfile=dist/webauthn.min.js",
"dev": "http-server"
},

@@ -17,4 +16,5 @@ "repository": {

"authentication",
"passwordless",
"webauthn"
"webauthn",
"passkeys",
"passwordless"
],

@@ -29,4 +29,5 @@ "author": "Arnaud Dagnelies",

"esbuild": "^0.15.8",
"http-server": "^14.1.1",
"typescript": "^4.8.3"
}
}

@@ -6,4 +6,11 @@ Passwordless.ID / webauthn

Check out the demo at https://passwordless.id/playground.html
<img src="demos/img/banner-biometric-auth.svg" />
Check out the demos:
- [Basic Demo](demos/basic.html)
- [Minimal Example (CDN)](demos/example-cdn.html)
- [Minimal Example (repository)](demos/example-raw.html)
- [Testing Playground](demos/playground.html)
Installation / Usage

@@ -19,3 +26,3 @@ --------------------

```js
import * as passwordless from '@passwordless-id/webauthn'
import * as webauthn from '@passwordless-id/webauthn'
```

@@ -27,3 +34,3 @@

<script type="module">
import * as passwordless from 'https://unpkg.com/@passwordless-id/webauthn@latest/dist/passwordless.min.js'
import * as webauthn from 'https://unpkg.com/@passwordless-id/webauthn@latest/dist/passwordless.min.js'
</script>

@@ -33,9 +40,10 @@ ```

Registration
------------
Example:
Example call:
```js
passwordless.register("Arnaud", "random-server-challenge", {
webauthn.register("Arnaud", "random-server-challenge", {
"authenticatorType": "auto",

@@ -48,2 +56,23 @@ "userVerification": "required",

Example response:
```json
{
"username": "Arnaud",
"challenge": "random-server-challenge",
"credential": {
"id": "RufE-HKYK2...",
"publicKey": "MIIBIjANBg...",
"algorithm": "RS256"
},
"authenticator": {
"isLocal": true,
"aaguid": "08987058-cadc-4b81-b6e1-30de50dcbe96",
"name": "Windows Hello Hardware Authenticator",
"attestation": "o2NmbXRjdH...",
"clientData": "eyJ0eXBlIj..."
}
}
```
Parameters:

@@ -55,9 +84,11 @@

Authentication
--------------
Example:
Example call:
```js
passwordless.login(["credentialIdBase64encoded"], "random-server-challenge", {
webauthn.login(["credentialIdBase64encoded"], "random-server-challenge", {
"authenticatorType": "auto",

@@ -69,6 +100,36 @@ "userVerification": "required",

Example response:
```json
{
"credentialId": "c8VC7q_TY0NvKIhcS_rafPLEvdw8GwePABH81QRNt4Y",
"userHash": "awopRTWFXAQrBPRAbEPFg3WUd4forBvMho7Ie4sxabE=",
"clientJson": {
"type": "webauthn.get",
"challenge": "ZTEyNGE0ZTAtNjg4NS00YzhlLWFhODktNTZkMjJhZDUxNGYz",
"origin": "http://localhost:8080",
"crossOrigin": false
},
"clientData": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWlRFeU5HRTBaVEF0TmpnNE5TMDBZemhsTFdGaE9Ea3ROVFprTWpKaFpEVXhOR1l6Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ==",
"signature": "J8PbSE9ZgC2JME9r2SYGY7WMDUKVDFby8WPXxSpXYfLpmfjimGed8oEqvUtD4UhvshjKV9FOlS0Dc8N8ILvIDL77gmUPeY6oZbTqrw9+2NgeXONM9hNDnxIjOUxekC8a3LY1HFq7aWy4v9I/gu1vD5NGSouvlzxJXPHcC30Bxu70EMcTwtz3EnRmQ3UGuZXjYO2xd2l2BsUgyI87c/wpquaCThrOPEf1PlzS4Larv5lE/Lfh4gQ2O/1TvmBcjtT/oSFkkb6hAgJp51/QbrUbnzdAtTtbGnSTOukM/HZ6yFY5i4oy3l+cJbwAGxEqFUU7yAdPrmTJdLeLmzimve58RA==",
"authenticatorJson": {
"rpIdHash": "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2M=",
"flags": {
"userPresent": true,
"userVerified": true,
"backupEligibility": false,
"backupState": false,
"attestedData": false,
"extensionsIncluded": false
},
"counter": 1
},
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MFAAAAAQ=="
}
```
Parameters:
- `credentialIds`: The list of credential IDs that can be used for signing.
- `challenge`: A server-side randomly generated string, the base64 encoded version will be signed.
- `challenge`: A server-side randomly generated string, the base64url encoded version will be signed.
- `options`: See below

@@ -91,6 +152,4 @@

Unlike the [webauthn protocol](), there are some significant differences.
Unlike the [webauthn protocol](), some defaults are different:
First, some defaults are different:
- The `timeout` is one minute by default.

@@ -100,8 +159,1 @@ - If the device can act as authenticator itself, it is preffered instead of asking which authenticator type to use.

Then, the response is also different, as plain JSON with values encoded in **Base64**. It does not use *Base64url* that the webauthn protocol favors. This was chosen for two reasons:
- These values should never appear in URLs anyway for both privacy and security reasons, so let's not encourage/suggest it.
- Many server framework have middleware to decode base64 values out-of-the box as byte arrays while base64url frequently requires some form of pre-processing.
Please also note that swapping the encoding from *base64* to *base64url* is the matter of replacing two characters in the string.
import * as authenticatorMetadata from './authenticatorMetadata.json'
import * as utils from './utils'
console.debug(authenticatorMetadata)
//console.debug(authenticatorMetadata)
export function parseAuthData(authData :ArrayBuffer) {

@@ -14,3 +13,3 @@ console.debug(authData)

let parsed :any = {
rpIdHash: utils.toBase64(authData.slice(0,32)),
rpIdHash: utils.toBase64url(authData.slice(0,32)),
flags: {

@@ -35,4 +34,4 @@ userPresent: !!(flags & 1),

aaguid: extractAaguid(authData),
credentialId: utils.toBase64(authData.slice(55, 55+credentialLength)),
publicKey: utils.toBase64(authData.slice(55+credentialLength, authData.byteLength)) // probably breaks if extensions are invoked
credentialId: utils.toBase64url(authData.slice(55, 55+credentialLength)),
publicKey: utils.toBase64url(authData.slice(55+credentialLength, authData.byteLength)) // probably breaks if extensions are invoked
}

@@ -39,0 +38,0 @@ }

@@ -14,12 +14,14 @@ /********************************

export function toBase64(buffer :ArrayBuffer) :string {
return btoa(parseBuffer(buffer))
export function isBase64url(txt :string) :boolean {
return txt.match(/^[a-zA-Z0-9\-_]+=*$/) !== null
}
export function parseBase64(txt :string) :ArrayBuffer {
return toBuffer(atob(txt))
export function toBase64url(buffer :ArrayBuffer) :string {
const txt = btoa(parseBuffer(buffer)) // base64
return txt.replaceAll('+', '-').replaceAll('/', '_')
}
export function parseBase64url(txt :string) :ArrayBuffer {
return parseBase64(txt.replace(/-/g, '+').replace(/_/g, '/'))
txt = txt.replaceAll('-', '+').replaceAll('_', '/') // base64url -> base64
return toBuffer(atob(txt))
}

@@ -26,0 +28,0 @@

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