A Firebase Extension for authentication with WebAuthn passkeys.
This package contains five tree-shakeable async methods for using FirebaseWebAuthn in components and a strongly-typed error object.
createUserWithPasskey: (auth: Auth, functions: Functions, name: string) => Promise<UserCredential>;
signInWithPasskey: (auth: Auth, functions: Functions) => Promise<UserCredential>;
linkWithPasskey: (auth: Auth, functions: Functions, name: string) => Promise<UserCredential>;
unlinkPasskey: (auth: Auth, functions: Functions) => Promise<void>;
verifyUserWithPasskey: (auth: Auth, functions: Functions) => Promise<void>;
All methods besides createUserWithPasskey
accept an optional factor
parameter of "first"
or "second"
.
Default behaviors were designed to maintain backwards compatibility and are described below:
signInWithPasskey(auth, functions) // Sign in and accept either credential.
signInWithPasskey(auth, functions, "first") // Sign in and only accept a first (1FA) factor credential.
signInWithPasskey(auth, functions, "second") // Sign in and only accept a second (2FA) factor credential.
linkWithPasskey(auth, functions, username) // Link a first (1FA) factor credential.
linkWithPasskey(auth, functions, username, "first") // Link a first (1FA) factor credential.
linkWithPasskey(auth, functions, username, "second") // Link a second (2FA) factor credential.
unlinkWithPasskey(auth, functions) // Unlink all credentials.
unlinkWithPasskey(auth, functions, "first") // Unlink all credentials.
unlinkWithPasskey(auth, functions, "second") // Unlink a second (2FA) factor credential.
verifyUserWithPasskey(auth, functions) // Verify the user and allow either credential.
verifyUserWithPasskey(auth, functions, "first") // Verify the user and allow only a first (1FA) factor credential.
verifyUserWithPasskey(auth, functions, "second") // Verify the user and allow only a second (2FA) factor credential.
Designed to be used like the Firebase JavaScript SDK:
import { createUserWithEmailAndPassword } from "firebase/auth";
import { createUserWithPasskey } from "@firebase-web-authn/browser";
class SignUpComponent {
constructor(
private readonly auth: Auth,
private readonly functions: Functions,
) {
// Firebase JavaScript SDK usage
this
.createUserWithEmailAndPassword = (email: string, password: string) => createUserWithEmailAndPassword(auth, email, password)
.then(() => void(0));
// FirebaseWebAuthn usage
this
.createUserWithPasskey = (name: string) => createUserWithPasskey(auth, functions, name)
.then(() => void(0));
}
public readonly createUserWithEmailAndPassword: (email: string, password: string) => Promise<void>;
public readonly createUserWithPasskey: (name: string) => Promise<void>;
}
Add .catch((err: FirebaseWebAuthnError): void => console.error(err))
to these for a detailed error object with a code
, message
, method
, and/or operation
. method
is present for Firebase errors, and operation
is present on all errors except Firebase errors from Auth methods:
import { FirebaseWebAuthnError } from "@firebase-web-authn/browser";
class FirebaseWebAuthnError extends Error {
code: `firebaseWebAuthn/${FirebaseError["code"] | "missing-auth" | "missing-user-doc" | "no-op" | "not-verified" | "user-doc-missing-challenge-field" | "user-doc-missing-passkey-fields" | "cancelled" | "invalid"}`;
message: FirebaseError["message"] | "No user is signed in." | "No user document was found in Firestore." | "No operation is needed." | "User not verified." | "User doc is missing challenge field from prior operation." | "User doc is missing passkey fields from prior operation.";
method?: "httpsCallableFromURL" | "signInAnonymously" | "signInWithCustomToken";
operation?: "clear challenge" | "clear credential" | "create authentication challenge" | "create reauthentication challenge" | "create registration challenge" | "verify authentication" | "verify reauthentication" | "verify registration";
}
- The anonymous sign-in provider must be enabled in Firebase.
-
onAuthStateChanged
callbacks are only fired upon starting auth or registration if your user is not already signed in anonymously. -
onIdTokenChanged
callbacks are fired upon successfully converting from an anonymous account to a WebAuthn account. - If you are using biometrics to confirm an action that will happen server-side, use methods from @firebase-web-authn/server.
- The
ext-firebase-web-authn
Firestore Database should not have rules permitting client-side access for security pattern reasons. - The
name
parameter is only used by the passkey manager and changes to it are not detectable by the browser.- If FirebaseWebAuthn is configured as an MFA provider, pass the existing identifier. This way it is stored alongside the user's primary credential.
- If FirebaseWebAuthn is your only auth provider, you can pass any recognizable value. If you expect users to have multiple usernameless accounts,
name
can be a user-generated account name ("Personal"/"Work"/etc.). With genericname
values consider passing something like "${FIRST_NAME} | Personal" for users who share a device with others.