{"id":19335033,"url":"https://github.com/gavinsawyer/firebase-web-authn","last_synced_at":"2025-04-07T17:07:53.631Z","repository":{"id":149930788,"uuid":"622409966","full_name":"gavinsawyer/firebase-web-authn","owner":"gavinsawyer","description":"A Firebase Extension for authentication with WebAuthn passkeys. Hire the developer: /in/gavinsawyer-dev.","archived":false,"fork":false,"pushed_at":"2024-10-11T17:22:39.000Z","size":4379,"stargazers_count":49,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-31T16:14:10.932Z","etag":null,"topics":["api","authentication","cloud-functions","firebase","monorepo","nx","serverless","typescript","web","webauthn"],"latest_commit_sha":null,"homepage":"https://extensions.dev/extensions/gavinsawyer/firebase-web-authn","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gavinsawyer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-02T02:47:52.000Z","updated_at":"2025-03-03T20:18:01.000Z","dependencies_parsed_at":"2025-01-17T12:12:57.517Z","dependency_job_id":"9dbd2cda-2caf-4f57-a945-5285c0f564bf","html_url":"https://github.com/gavinsawyer/firebase-web-authn","commit_stats":{"total_commits":89,"total_committers":1,"mean_commits":89.0,"dds":0.0,"last_synced_commit":"7eebfca78b5dd06e5762ed2be1c655c5d105c919"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinsawyer%2Ffirebase-web-authn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinsawyer%2Ffirebase-web-authn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinsawyer%2Ffirebase-web-authn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gavinsawyer%2Ffirebase-web-authn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gavinsawyer","download_url":"https://codeload.github.com/gavinsawyer/firebase-web-authn/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247694876,"owners_count":20980733,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","authentication","cloud-functions","firebase","monorepo","nx","serverless","typescript","web","webauthn"],"created_at":"2024-11-10T03:04:32.727Z","updated_at":"2025-04-07T17:07:53.613Z","avatar_url":"https://github.com/gavinsawyer.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FirebaseWebAuthn\nA Firebase Extension for authentication with WebAuthn passkeys.\n\n[![GitHub workflow status](https://img.shields.io/github/actions/workflow/status/gavinsawyer/firebase-web-authn/ci.yml)](https://github.com/gavinsawyer/firebase-web-authn/actions/workflows/ci.yml)\n[![View in Extensions Hub](https://img.shields.io/static/v1?label=\u0026message=View%20in%20Extensions%20Hub\u0026logo=firebase)](https://extensions.dev/extensions/gavinsawyer/firebase-web-authn)\n#### Demo: https://firebase-web-authn.dev\n\n### Summary\nWebAuthn enables creating an account or signing in with as few as two clicks and doesn't ask the user to remember anything. This extension addresses a [popular feature request](https://github.com/firebase/firebase-js-sdk/issues/2123) for WebAuthn as an authentication provider in Firebase.\n\nThis is a monorepo with five packages including an easy-to-install [Firebase Extension](libs/extension) and small [Browser SDK](libs/browser). The major version is tracking that of the [Firebase JavaScript SDK](https://www.npmjs.com/package/firebase) and mirrors its implementation patterns.\n\nFeatures include:\n- creating and signing in users with passkeys,\n- linking and unlinking existing users to passkeys,\n- prompting signed-in users with a biometric verification request,\n- securely determining when a user was verified last with biometrics, and\n- assigning backup passkeys **(🎉 New in v10.3.0)**.\n## [@firebase-web-authn/extension](libs/extension)\nThis package conforms to the Firebase Extensions spec and is available from either NPM or the Extensions Hub.\n\n[![Latest version in NPM](https://img.shields.io/npm/v/@firebase-web-authn/extension?logo=npm)](https://www.npmjs.com/package/@firebase-web-authn/extension)\n### Installation\n[![Install](https://img.shields.io/static/v1?label=\u0026message=Install%20in%20Firebase%20console\u0026logo=firebase\u0026color=blue)](https://console.firebase.google.com/u/0/project/_/extensions/install?ref=gavinsawyer%2Ffirebase-web-authn)\n\nTo install from the Extensions Hub, click the button above or run the following commands in your project root:\n```\n% firebase ext:install gavinsawyer/firebase-web-authn\n```\nTo install from NPM, run the following commands in your project root:\n```\n% npm i @firebase-web-authn/extension --save-dev\n% firebase ext:install ./node_modules/@firebase-web-authn/extension\n```\nUsing NPM is recommended to receive updates to the extension alongside other FirebaseWebAuthn dependencies.\n### Prerequisites\nBefore installing this extension, you'll need to set up these services in your project. This must be done both in the Firebase Console and initialized in the application:\n- App Check with reCAPTCHA Enterprise or v3\n- Authentication with the anonymous provider\n- Firestore\n- Functions\n### Additional setup:\n1. Create a Firestore Database to store public key credentials with the ID `ext-firebase-web-authn` and location matching the function deployment. It is recommended to choose either `nam5` in North America or `eur3` in Europe and to enable delete protection:\n\n    ```\n    % firebase firestore:databases:create ext-firebase-web-authn --location ${MULTI_REGION_NAME} --delete-protection ENABLED\n    ```\n\n2. As of July 2024, [supported roles for Firebase Extensions](https://firebase.google.com/docs/extensions/publishers/access#supported-roles) do not include `iam.serviceAccounts.signBlob` or `serviceusage.services.use` which are needed for custom auth providers.\n   - After deploying the extension, grant the `Service Account Token Creator` and `Service Usage Consumer` roles to the extension's service account in [IAM](https://console.cloud.google.com/iam-admin/iam) under `Firebase Extensions firebase-web-authn service account` \u003e Edit \u003e Assign roles.\n   - If the service account isn't appearing, click `Grant Access` and enter its address as `ext-firebase-web-authn@${PROJECT_ID}.iam.gserviceaccount.com`\n3. The browser must reach FirebaseWebAuthn from the same domain as your website. Modify your `firebase.json` to include a rewrite on each app where you'd like to use passkeys:\n\n    ```json\n    {\n      \"hosting\": [\n        {\n          \"target\":   \"...\",\n          \"rewrites\": [\n            {\n              \"source\":   \"/firebase-web-authn-api\",\n              \"function\": \"ext-firebase-web-authn-api\"\n            }\n          ]\n        }\n      ]\n    }\n    ```\n## [@firebase-web-authn/browser](libs/browser)\nThis package contains five tree-shakeable async methods for using FirebaseWebAuthn in components and a strongly-typed error object.\n\n[![FirebaseWebAuthn version](https://img.shields.io/npm/v/@firebase-web-authn/browser?logo=npm)](https://www.npmjs.com/package/@firebase-web-authn/browser)\n[![Firebase JS SDK version](https://img.shields.io/npm/dependency-version/@firebase-web-authn/browser/firebase?label=Firebase%20JS%20SDK\u0026logo=firebase)](https://www.npmjs.com/package/firebase)\n### Methods\n```ts\ncreateUserWithPasskey: (auth: Auth, functions: Functions, name: string) =\u003e Promise\u003cUserCredential\u003e;\n    signInWithPasskey: (auth: Auth, functions: Functions)               =\u003e Promise\u003cUserCredential\u003e;\n      linkWithPasskey: (auth: Auth, functions: Functions, name: string) =\u003e Promise\u003cUserCredential\u003e;\n        unlinkPasskey: (auth: Auth, functions: Functions)               =\u003e Promise\u003cvoid\u003e;\nverifyUserWithPasskey: (auth: Auth, functions: Functions)               =\u003e Promise\u003cvoid\u003e;\n```\n#### 🎉 2FA passkeys are here in ^10.3.0!\nAll methods besides `createUserWithPasskey` accept an optional `factor` parameter of `\"first\"` or `\"second\"`.\n\nDefault behaviors were designed to maintain backwards compatibility and are described below:\n```ts\n          signInWithPasskey(auth, functions) // Sign in and accept either credential.\n signInWithPasskey(auth, functions, \"first\") // Sign in and only accept a first (1FA) factor credential.\nsignInWithPasskey(auth, functions, \"second\") // Sign in and only accept a second (2FA) factor credential.\n```\n```ts\n          linkWithPasskey(auth, functions, username) // Link a first (1FA) factor credential.\n linkWithPasskey(auth, functions, username, \"first\") // Link a first (1FA) factor credential.\nlinkWithPasskey(auth, functions, username, \"second\") // Link a second (2FA) factor credential.\n```\n```ts\n          unlinkWithPasskey(auth, functions) // Unlink all credentials.\n unlinkWithPasskey(auth, functions, \"first\") // Unlink all credentials.\nunlinkWithPasskey(auth, functions, \"second\") // Unlink a second (2FA) factor credential.\n```\n```ts\n          verifyUserWithPasskey(auth, functions) // Verify the user and allow either credential.\n verifyUserWithPasskey(auth, functions, \"first\") // Verify the user and allow only a first (1FA) factor credential.\nverifyUserWithPasskey(auth, functions, \"second\") // Verify the user and allow only a second (2FA) factor credential.\n```\nDesigned to be used like the Firebase JavaScript SDK:\n```ts\nimport { createUserWithEmailAndPassword } from \"firebase/auth\";\nimport { createUserWithPasskey }          from \"@firebase-web-authn/browser\";\n```\n```ts\nclass SignUpComponent {\n\n  constructor(\n    private readonly auth: Auth,\n    private readonly functions: Functions,\n  ) {\n    // Firebase JavaScript SDK usage\n    this\n      .createUserWithEmailAndPassword = (email: string, password: string) =\u003e createUserWithEmailAndPassword(auth, email, password)\n      .then(() =\u003e void(0));\n\n    // FirebaseWebAuthn usage\n    this\n      .createUserWithPasskey = (name: string) =\u003e createUserWithPasskey(auth, functions, name)\n      .then(() =\u003e void(0));\n\n  }\n\n  public readonly createUserWithEmailAndPassword: (email: string, password: string) =\u003e Promise\u003cvoid\u003e;\n  public readonly createUserWithPasskey: (name: string) =\u003e Promise\u003cvoid\u003e;\n\n}\n```\nAdd `.catch((err: FirebaseWebAuthnError): void =\u003e 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:\n```ts\nimport { FirebaseWebAuthnError } from \"@firebase-web-authn/browser\";\n```\n```ts\nclass FirebaseWebAuthnError extends Error {\n  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\"}`;\n  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.\";\n  method?: \"httpsCallableFromURL\" | \"signInAnonymously\" | \"signInWithCustomToken\";\n  operation?: \"clear challenge\" | \"clear credential\" | \"create authentication challenge\" | \"create reauthentication challenge\" | \"create registration challenge\" | \"verify authentication\" | \"verify reauthentication\" | \"verify registration\";\n}\n```\n### Caveats\n- The anonymous sign-in provider must be enabled in Firebase.\n- `onAuthStateChanged` callbacks are only fired upon starting auth or registration if your user is not already signed in anonymously.\n- `onIdTokenChanged` callbacks are fired upon successfully converting from an anonymous account to a WebAuthn account.\n- If you are using biometrics to confirm an action that will happen server-side, use methods from [@firebase-web-authn/server](libs/server).\n- The `ext-firebase-web-authn` Firestore Database should not have rules permitting client-side access for security pattern reasons.\n- The `name` parameter is only used by the passkey manager and changes to it are not detectable by the browser.\n  - If FirebaseWebAuthn is configured as an MFA provider, pass the existing identifier. This way it is stored alongside the user's primary credential.\n  - 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 generic `name` values consider passing something like \"${FIRST_NAME} | Personal\" for users who share a device with others.\n## [@firebase-web-authn/server](libs/server)\nThis package contains five tree-shakeable async methods for using FirebaseWebAuthn in a secure context.\n\n[![FirebaseWebAuthn version](https://img.shields.io/npm/v/@firebase-web-authn/server?logo=npm)](https://www.npmjs.com/package/@firebase-web-authn/server)\n[![Firebase Admin SDK version](https://img.shields.io/npm/dependency-version/@firebase-web-authn/server/firebase-admin?label=Firebase%20Admin%20SDK\u0026logo=firebase)](https://www.npmjs.com/package/firebase-admin)\n### Methods\n\n```ts\n         credentials: (uid: string, app?: App) =\u003e Promise\u003c{ [key in WebAuthnUserCredentialFactor]: WebAuthnUserCredential | null }\u003e;\n  lastCredentialUsed: (uid: string, app?: App) =\u003e Promise\u003cWebAuthnUserCredentialFactor | null\u003e;\n         lastPresent: (uid: string, app?: App) =\u003e Promise\u003cTimestamp | null\u003e;\n        lastVerified: (uid: string, app?: App) =\u003e Promise\u003cTimestamp | null\u003e;\n lastWebAuthnProcess: (uid: string, app?: App) =\u003e Promise\u003cWebAuthnProcess | null\u003e;\nwebAuthnUserDocument: (uid: string, app?: App) =\u003e Promise\u003cWebAuthnUserDocument | null\u003e;\n```\nDesigned to be used within Firebase Functions or another secure context with access to Firestore to check users' status with FirebaseWebAuthn:\n```ts\nimport { getApps, initializeApp } from \"firebase-admin/app\";\nimport { lastVerified }           from \"@firebase-web-authn/server\";\n```\n```ts\ngetApps().length === 0 \u0026\u0026 initializeApp();\n\n// If the user was verified within the past 30 seconds, proceed. Otherwise, ask for reverification:\n(await lastVerified(uid))?.seconds \u003e (Date.now() / 1000) - 30 ?\n  proceed() :\n  askForReverification();\n```\nIf your check involves multiple pieces of data from `WebAuthnUserDocument`, use the `webAuthnUserDocument` method to reduce Firestore calls:\n```ts\n// If the user was verified with their first-factor credential within the past 30 seconds, proceed. Otherwise, ask for reverification:\n(await webAuthnUserDocument(user.uid).then\u003cboolean\u003e(\n  (webAuthnUserDocument: WebAuthnUserDocument): boolean =\u003e webAuthnUserDocument.lastVerified?.seconds \u003e (Date.now() / 1000) - 30 \u0026\u0026 webAuthnUserDocument.lastCredentialUsed === \"first\",\n)) ?\n  proceed() :\n  askForReverification();\n```\n## Other packages\n- [@firebase-web-authn/api](libs/api): This package contains a Firebase Function that registers and authenticates WebAuthn passkeys, manages public key credentials in Firestore, and cleans up data if the user cancels the process or unlinks a passkey.\n- [@firebase-web-authn/types](libs/types): This package contains types and interfaces used internally by FirebaseWebAuthn and for implementing it in a secure context.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinsawyer%2Ffirebase-web-authn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgavinsawyer%2Ffirebase-web-authn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgavinsawyer%2Ffirebase-web-authn/lists"}