Skip to content

Commit

Permalink
fixes V2: authenticate() function doesn't handle string credentialIds #…
Browse files Browse the repository at this point in the history
  • Loading branch information
dagnelies committed Aug 1, 2024
1 parent 1b5a792 commit e104419
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 27 deletions.
7 changes: 5 additions & 2 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ const authentication = await client.authenticate({
/* Required */
challenge: "A server-side randomly generated byte array as base64url encoded",
/* Optional */
allowCredentials: ["credential-id-1", "credential-id-2"],
allowCredentials: [{id:'my-credential-id', transports:['internal']}, ...],
timeout: 60000
})
```

If you already know the supported passkeys for the account, passkey selection can be skipped with `allowCredentials`.
Without, the platform's default passkey slection dialog will be triggered.

The following options are available.

Expand All @@ -67,7 +69,8 @@ The following options are available.
| `userVerification`| `preferred` | Whether the user verification (using local authentication like fingerprint, PIN, etc.) is `required`, `preferred` or `discouraged`.
| `hints` | `[]` | Which device to use as authenticator, by order of preference. Possible values: `client-device`, `security-key`, `hybrid` (delegate to smartphone).
| `domain` | `window.location.hostname` | By default, the current domain name is used. Also known as "relying party id". You may want to customize it for ...
| `mediation` | | See https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get#mediation
| `allowedCredentials` | The list of credentials and the transports it supports. Used to skip passkey selection. Either a list of credential ids (discouraged) or list of credential objects with `id` and supported `transports` (recommended).
| `autofill` | `false` | See concepts



Expand Down
2 changes: 1 addition & 1 deletion docs/demos/js/webauthn.min.js

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion docs/registration.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ The result `registration` object looks like this:
"credential": {
"id": "3924HhJdJMy_svnUowT8eoXrOOO6NLP8SK85q2RPxdU",
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgyYqQmUAmDn9J7dR5xl-HlyAA0R2XV5sgQRnSGXbLt_xCrEdD1IVvvkyTmRD16y9p3C2O4PTZ0OF_ZYD2JgTVA==",
"algorithm": "ES256"
"algorithm": "ES256",
"transports": ["internal", "hybrid"]
},
"authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFAAAAAAiYcFjK3EuBtuEw3lDcvpYAIN_duB4SXSTMv7L51KME_HqF6zjjujSz_EivOatkT8XVpQECAyYgASFYIIMmKkJlAJg5_Se3UecZfh5cgANEdl1ebIEEZ0hl2y7fIlgg8QqxHQ9SFb75Mk5kQ9esvadwtjuD02dDhf2WA9iYE1Q=",
"clientData": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoiYTdjNjFlZjktZGMyMy00ODA2LWI0ODYtMjQyODkzOGE1NDdlIiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwIiwiY3Jvc3NPcmlnaW4iOmZhbHNlfQ=="
Expand Down
28 changes: 19 additions & 9 deletions src/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AuthenticateOptions, AuthenticationJSON, AuthenticatorTransport, PublicKeyCredentialHints, RegisterOptions, RegistrationJSON, User, WebAuthnCreateOptions, WebAuthnGetOptions } from './types.js'
import { AuthenticateOptions, AuthenticationJSON, Base64URLString, CredentialDescriptor, ExtendedAuthenticatorTransport, PublicKeyCredentialHints, RegisterOptions, RegistrationJSON, User, WebAuthnCreateOptions, WebAuthnGetOptions } from './types.js'
import * as utils from './utils'

/**
Expand Down Expand Up @@ -155,13 +155,7 @@ export async function authenticate(options: AuthenticateOptions): Promise<Authen
let authOptions: WebAuthnGetOptions = {
challenge: utils.parseBase64url(options.challenge),
rpId: options.domain ?? window.location.hostname,
allowCredentials: options.allowCredentials?.map(cred => {
return {
id: utils.parseBase64url(cred.id),
type: 'public-key',
transports: cred.transports as any,
}
}),
allowCredentials: options.allowCredentials?.map(toPublicKeyCredentialDescriptor),
hints: options.hints,
userVerification: options.userVerification,
timeout: options.timeout,
Expand Down Expand Up @@ -204,4 +198,20 @@ export async function authenticate(options: AuthenticateOptions): Promise<Authen
}

return json
}
}

function toPublicKeyCredentialDescriptor(cred: Base64URLString | CredentialDescriptor): PublicKeyCredentialDescriptor {
if(typeof cred === 'string') {
return {
id: utils.parseBase64url(cred),
type: 'public-key'
}
}
else {
return {
id: utils.parseBase64url(cred.id),
type: 'public-key',
transports: cred.transports as AuthenticatorTransport[]
}
}
}
1 change: 1 addition & 0 deletions src/parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export function toRegistrationInfo(registrationJson :RegistrationJSON, authentic
id: registrationJson.id,
publicKey: registrationJson.response.publicKey,
algorithm: getAlgoName(registrationJson.response.publicKeyAlgorithm),
transports: registrationJson.response.transports
},
synced: authenticator.flags.backupEligibility,
user: registrationJson.user as UserInfo, // That's specific to this library
Expand Down
18 changes: 7 additions & 11 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ export interface User {
*/
export interface CredentialDescriptor {
id: Base64URLString,
transports?: AuthenticatorTransport[]
transports: ExtendedAuthenticatorTransport[]
}

export interface AuthenticateOptions extends CommonOptions {
allowCredentials?: CredentialDescriptor[]
allowCredentials?: (CredentialDescriptor | string)[]
conditional?: boolean
}

Expand Down Expand Up @@ -93,7 +93,7 @@ export interface AuthenticatorAttestationResponseJSON {
attestationObject: Base64URLString;
authenticatorData: Base64URLString;
clientDataJSON: Base64URLString;
transports: AuthenticatorTransport[];
transports: ExtendedAuthenticatorTransport[];
publicKey: Base64URLString;
publicKeyAlgorithm: COSEAlgorithmIdentifier;
}
Expand Down Expand Up @@ -130,15 +130,10 @@ export interface AuthenticatorAssertionResponseJSON {
/**
* WebAuthn added transports that are not yet defined in the DOM definitions.
* However, it's partly obsoleted by the `hints` in the registration/authentication request.
*
* https://w3c.github.io/webauthn/#enumdef-authenticatortransport
*/
export type AuthenticatorTransport =
| 'ble'
| 'cable'
| 'hybrid'
| 'internal'
| 'nfc'
| 'smart-card'
| 'usb';
export type ExtendedAuthenticatorTransport = AuthenticatorTransport | 'smart-card'; // missing in the current DOM types


/************************** PARSED **************************/
Expand Down Expand Up @@ -203,6 +198,7 @@ export interface CredentialInfo {
id: string
publicKey: string
algorithm: NamedAlgo
transports: ExtendedAuthenticatorTransport[]
}

export interface AuthenticatorInfo {
Expand Down

0 comments on commit e104419

Please sign in to comment.