agentsclimarketplace

Better auth firebase auth

Skill yultyyev/better-auth-firebase-auth

Use Firebase Authentication (Phone SMS OTP, Google, Email) with Better Auth sessions, organizations, and plugins. No Twilio needed for phone auth.

Install
npx -y skills add yultyyev/better-auth-firebase-auth

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 17 stars17 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Add Firebase Authentication (Phone SMS OTP, Google Sign-In, Email/Password) to a Better Auth app using the better-auth-firebase-auth plugin. Use when adding phone authentication to Better Auth without Twilio, integrating Firebase Auth with Better Auth sessions, working with the better-auth-firebase-auth package, or deciding between Firebase Phone Auth and Better Auth's built-in phoneNumber plugin.

SKILL.md

7.1 KB, as published. Nobody here has run it

Firebase Auth + Better Auth

better-auth-firebase-auth bridges Firebase Authentication identity providers into Better Auth sessions. Firebase verifies the user; Better Auth owns the session, users, and plugins.

Package: better-auth-firebase-authGitHub · npm


Decision: Firebase Phone Auth vs Better Auth phoneNumber plugin

Use better-auth-firebase-auth when:

  • You want phone auth without setting up Twilio or any SMS provider
  • You are already using Firebase in your project
  • You want Google to manage SMS delivery, reCAPTCHA, and fraud prevention

Use Better Auth's built-in phoneNumber plugin when:

  • You want no Firebase dependency
  • You need a specific SMS provider for compliance or cost reasons

Install

pnpm add better-auth-firebase-auth firebase-admin firebase better-auth

Import paths — CRITICAL

Always split server and client imports. Never import firebase-admin into client bundles.

// Server ONLY (API routes, server components, server actions)
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";

// Client ONLY (React components, browser code)
import { firebaseAuthClientPlugin } from "better-auth-firebase-auth/client";

Server setup (lib/auth.ts)

import { betterAuth } from "better-auth";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
import { cert, getApps, initializeApp } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";

// Initialize Firebase Admin once
if (getApps().length === 0) {
  initializeApp({
    credential: cert({
      projectId: process.env.FIREBASE_PROJECT_ID!,
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL!,
      privateKey: process.env.FIREBASE_PRIVATE_KEY!.replace(/\\n/g, "\n"),
    }),
  });
}

export const auth = betterAuth({
  plugins: [
    firebaseAuthPlugin({
      useClientSideTokens: true, // client gets Firebase token, server only verifies
      firebaseAdminAuth: getAuth(),
    }),
  ],
});

Client setup (lib/auth-client.ts)

import { createAuthClient } from "better-auth/react";
import { firebaseAuthClientPlugin } from "better-auth-firebase-auth/client";

export const authClient = createAuthClient({
  plugins: [firebaseAuthClientPlugin()],
});

Phone Authentication (SMS OTP)

Firebase sends the SMS and verifies the OTP. No Twilio needed.

Prerequisite: Enable Phone in Firebase Console → Authentication → Sign-in method.

import { getAuth, RecaptchaVerifier, signInWithPhoneNumber } from "firebase/auth";
import { authClient } from "@/lib/auth-client";

const firebaseAuth = getAuth();

// 1. Send OTP
const verifier = new RecaptchaVerifier(firebaseAuth, "recaptcha-container", {
  size: "invisible",
});
const confirmation = await signInWithPhoneNumber(firebaseAuth, "+15555550100", verifier);

// 2. Confirm OTP → get Firebase token → create Better Auth session
const result = await confirmation.confirm(userEnteredCode);
const idToken = await result.user.getIdToken();
await authClient.signInWithPhone({ idToken });

Phone-only users (no email on their Firebase account) get a stable synthetic email: ${uid}@firebase.local by default. Override with getPhoneUserFallbackEmail.


Google Sign-In

import { getAuth, GoogleAuthProvider, signInWithPopup } from "firebase/auth";

const result = await signInWithPopup(getAuth(), new GoogleAuthProvider());
const idToken = await result.user.getIdToken();
await authClient.signInWithGoogle({ idToken });

Email/Password

import { getAuth, signInWithEmailAndPassword } from "firebase/auth";

const credential = await signInWithEmailAndPassword(getAuth(), email, password);
const idToken = await credential.user.getIdToken();
await authClient.signInWithEmail({ idToken });

Password reset is handled by Firebase — no email provider (SendGrid, Resend) needed:

await authClient.sendPasswordReset({ email });

Using with the Firestore adapter

To store Better Auth data in Firestore, combine with better-auth-firestore:

import { firestoreAdapter } from "better-auth-firestore";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
import { getAuth } from "firebase-admin/auth";
import { getFirestore } from "firebase-admin/firestore";

export const auth = betterAuth({
  database: firestoreAdapter({ firestore: getFirestore() }),
  plugins: [firebaseAuthPlugin({ firebaseAdminAuth: getAuth() })],
});

Remember to create the required Firestore composite index on the verification collection — see better-auth-firestore.


Key options

OptionDefaultNotes
useClientSideTokenstruefalse = server handles Firebase client SDK (needs firebaseConfig)
overrideEmailPasswordFlowfalseIntercept Better Auth's /sign-in/email and /sign-up/email routes
serverSideOnlyfalseNo endpoints registered; use hooks only
sessionExpiresInDays7Better Auth session lifetime
passwordResetUrlCustom URL for password reset page
getPhoneUserFallbackEmail${uid}@firebase.localStable email for phone-only users

Runtime support

RuntimeSupported
Node 18+
Next.js on Vercel (Node.js runtime)✅ Recommended
Cloud Functions / Cloud Run
Vercel Edge Runtime (runtime = 'edge')❌ Admin SDK requires Node.js
Cloudflare Workers❌ Admin SDK requires Node.js

Note: Vercel deploys work fine — the restriction is only when you explicitly opt into the Edge Runtime (export const runtime = 'edge'). The default Node.js serverless runtime on Vercel is fully supported.


Common mistakes

  • Importing firebaseAuthPlugin in client code — crashes on firebase-admin. Always use the /server path on the server and /client path in the browser.
  • Forgetting to enable the provider in Firebase Console — Phone, Google, and Email/Password must each be explicitly enabled under Authentication → Sign-in method.
  • Missing reCAPTCHA containersignInWithPhoneNumber requires a RecaptchaVerifier with a DOM element id. For invisible reCAPTCHA use size: "invisible".
  • Firebase Admin not initialized before getAuth() — call initializeApp() once before passing getAuth() to the plugin.
  • Using overrideEmailPasswordFlow: true without firebaseConfig — throws at startup. This mode requires the Firebase client SDK config.
  • FIREBASE_PRIVATE_KEY with literal \n — Always call .replace(/\\n/g, "\n") on the key before passing to cert().

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.