Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
dagnelies committed Dec 30, 2022
1 parent 82f1641 commit f6e63f0
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 43 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Particularly linux and "exotic" web browsers might not have support yet.
await client.isLocalAuthenticator()
```

This promise returns `true` or `false` depending on whether the device itself can act as authenticator. Otherwise, an "extern" authenticator like a smartphone or usb security key can be used. This information is mainly used for information messages and user guidance.
This promise returns `true` or `false` depending on whether the device itself can act as authenticator. Otherwise, a "roaming" authenticator like a smartphone or usb security key can be used. This information is mainly used for information messages and user guidance.



Expand Down Expand Up @@ -340,10 +340,10 @@ The following options are available for both `register` and `authenticate`.
- `timeout`: Number of milliseconds the user has to respond to the biometric/PIN check. *(Default: 60000)*
- `userVerification`: Whether to prompt for biometric/PIN check or not. *(Default: "required")*
- `authenticatorType`: Which device to use as authenticator. Possible values:
- `'auto'`: if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for an external device. *(Default)*
- `'auto'`: if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for a roaming device. *(Default)*
- `'local'`: use the local device (using TouchID, FaceID, Windows Hello or PIN)
- `'extern'`: use an external device (security key or connected phone)
- `'both'`: prompt the user to choose between local or external device. The UI and user interaction in this case is platform specific.
- `'roaming'`: use a roaming device (security key or connected phone)
- `'both'`: prompt the user to choose between local or roaming device. The UI and user interaction in this case is platform specific.
- `attestation`: (Only for registration) If enabled, the device attestation and clientData will be provided as base64 encoded binary data. Note that this is not available on some platforms. *(Default: false)*
- `debug`: If enabled, parses the "data" objects and provide it in a "debug" properties.

Expand Down
13 changes: 11 additions & 2 deletions demos/basic.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<b-input v-model="username" placeholder="Username" @input="checkIsRegistered()" autocomplete="webauthn username"></b-input>
</b-field>
<b-field>
<b-checkbox v-model="isExternal">Use extern authenticator</b-checkbox>
<b-checkbox v-model="isRoaming">Use roaming authenticator (phone, usb key...)</b-checkbox>
</b-field>
<div>
<b-button type="is-primary" @click="register()" :disabled="!username">Register device</b-button>
Expand All @@ -32,7 +32,16 @@
</template>
<template v-if="isAuthenticated">
<p>{{'Hello ' + username + '!'}}</p>
<hr/>
<section v-if="registrationData && !authenticationData" style="text-align: left;">
<p><b>Credential ID:</b> {{registrationData.credential.id}}</p>
<p><b>Public Key:</b> {{registrationData.credential.publicKey.substring(0,32)}}...</p>
<p><b>Algorithm:</b> {{registrationData.credential.algorithm}}</p>
<p><b>Authenticator Name:</b> {{registrationData.authenticator.name}}</p>
</section>
<section v-if="authenticationData" style="text-align: left;">
<p><b>Credential ID:</b> {{authenticationData.credentialId}}</p>
<p><b>Signature:</b> {{authenticationData.signature.substring(0,32)}}...</p>
</section>
<div>
<b-button type="is-primary" @click="logout()">Sign Out</b-button>
</div>
Expand Down
47 changes: 30 additions & 17 deletions demos/js/basic.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,62 @@
import { client } from '../../dist/webauthn.min.js'
import { client, parsers } from '../../dist/webauthn.min.js'

const app = new Vue({
el: '#app',
data: {
username: null,
isRegistered: false,
isAuthenticated: false,
isExternal: false
isRoaming: false,
registrationData: null,
authenticationData: null
},
methods: {
async checkIsRegistered() {
console.log(this.username + ' => ' + !!window.localStorage.getItem(this.username))
this.isRegistered = !!window.localStorage.getItem(this.username)
},
async register() {
let res = await client.register(this.username, window.crypto.randomUUID(),{authType: this.isExternal ? 'extern' : 'auto'})
let res = await client.register(this.username, window.crypto.randomUUID(), { authType: this.isRoaming ? 'roaming' : 'auto' })
console.debug(res)

const parsed = parsers.parseRegistration(res)
console.log(parsed)

window.localStorage.setItem(this.username, parsed.credential.id)
this.isAuthenticated = true
this.registrationData = parsed

this.$buefy.toast.open({
message: 'Registered!',
type: 'is-success'
message: 'Registered!',
type: 'is-success'
})

console.log(res)

this.isAuthenticated = true;
window.localStorage.setItem(this.username, res.credential.id)
await this.checkIsRegistered()
},
async login() {
let credentialId = window.localStorage.getItem(this.username)
let res = await client.authenticate(credentialId ? [credentialId] : [], window.crypto.randomUUID(), {isExternal: this.isExternal})
console.log(res)
let res = await client.authenticate(credentialId ? [credentialId] : [], window.crypto.randomUUID(), { authType: this.isRoaming ? 'roaming' : 'auto' })
console.debug(res)

const parsed = parsers.parseAuthentication(res)
console.log(parsed)

this.isAuthenticated = true
this.authenticationData = parsed

this.isAuthenticated = true;
this.$buefy.toast.open({
message: 'Signed in!',
type: 'is-success'
message: 'Signed in!',
type: 'is-success'
})
},
async logout() {
this.isAuthenticated = false;
this.$buefy.toast.open({
message: 'Signed out!',
type: 'is-success'
message: 'Signed out!',
type: 'is-success'
})

this.authenticationData = null
this.registrationData = null
}
}
})
4 changes: 2 additions & 2 deletions demos/playground.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ <h2 class="title">Registration</h2>
<b-select v-model="registration.options.authenticatorType" expanded>
<option>auto</option>
<option>local</option>
<option>extern</option>
<option>roaming</option>
<option>both</option>
</b-select>
<div class="hint">Which device to use as authenticator.</div>
Expand Down Expand Up @@ -134,7 +134,7 @@ <h2 class="title">Authentication</h2>
<b-select v-model="authentication.options.authenticatorType" expanded>
<option>auto</option>
<option>local</option>
<option>extern</option>
<option>roaming</option>
<option>both</option>
</b-select>
<div class="hint">Which device to use as authenticator.</div>
Expand Down
2 changes: 1 addition & 1 deletion dist/webauthn.min.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/webauthn.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@passwordless-id/webauthn",
"version": "1.1.0",
"version": "1.2.0",
"description": "A small wrapper around the webauthn protocol to make one's life easier.",
"type": "module",
"main": "dist/esm/index.js",
Expand Down
22 changes: 11 additions & 11 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function isLocalAuthenticator() :Promise<boolean> {
async function getAuthAttachment(authType :AuthType) :Promise<AuthenticatorAttachment|undefined> {
if(authType === "local")
return "platform";
if(authType === "extern")
if(authType === "roaming" || authType === "extern")
return "cross-platform";
if(authType === "both")
return undefined // The webauthn protocol considers `null` as invalid but `undefined` as "both"!
Expand Down Expand Up @@ -60,11 +60,11 @@ function getAlgoName(num :NumAlgo) :NamedAlgo {
* @param {Object} [options] Optional parameters.
* @param {number} [options.timeout=60000] Number of milliseconds the user has to respond to the biometric/PIN check.
* @param {'required'|'preferred'|'discouraged'} [options.userVerification='required'] Whether to prompt for biometric/PIN check or not.
* @param {'auto'|'local'|'extern'|'both'} [options.authenticatorType='auto'] Which device to use as authenticator.
* 'auto': if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for an external device.
* @param {'auto'|'local'|'roaming'|'both'} [options.authenticatorType='auto'] Which device to use as authenticator.
* 'auto': if the local device can be used as authenticator it will be preferred. Otherwise it will prompt for a roaming device.
* 'local': use the local device (using TouchID, FaceID, Windows Hello or PIN)
* 'extern': use an external device (security key or connected phone)
* 'both': prompt the user to choose between local or external device. The UI and user interaction in this case is platform specific.
* 'roaming': use a roaming device (security key or connected phone)
* 'both': prompt the user to choose between local or roaming device. The UI and user interaction in this case is platform specific.
* @param {boolean} [attestation=false] If enabled, the device attestation and clientData will be provided as Base64url encoded binary data.
* Note that this is not available on some platforms.
*/
Expand Down Expand Up @@ -131,23 +131,23 @@ async function getTransports(authType :AuthType) :Promise<AuthenticatorTransport

// 'hybrid' was added mid-2022 in the specs and currently not yet available in the official dom types
// @ts-ignore
const extern :AuthenticatorTransport[] = ['hybrid', 'usb', 'ble', 'nfc']
const roaming :AuthenticatorTransport[] = ['hybrid', 'usb', 'ble', 'nfc']

if(authType === "local")
return local
if(authType === "extern")
return extern
if(authType == "roaming" || authType === "extern")
return roaming
if(authType === "both")
return [...local, ...extern]
return [...local, ...roaming]

// the default case: "auto", depending on device capabilities
try {
if(await isLocalAuthenticator())
return local
else
return extern
return roaming
} catch(e) {
return [...local, ...extern]
return [...local, ...roaming]
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

export type AuthType = 'auto' | 'local' | 'extern' | 'both'
// 'extern' is deprecated in favor of 'roaming' but kept for compatibility purposes
export type AuthType = 'auto' | 'local' | 'extern' | 'roaming' | 'both'


// TODO: although algo "-8" is currently only used optionally by a few security keys,
Expand Down

0 comments on commit f6e63f0

Please sign in to comment.