https://github.com/yultyyev/better-auth-firebase-auth
Firebase Authentication plugin for Better Auth
https://github.com/yultyyev/better-auth-firebase-auth
authentication better-auth firebase firebase-auth typescript
Last synced: 2 months ago
JSON representation
Firebase Authentication plugin for Better Auth
- Host: GitHub
- URL: https://github.com/yultyyev/better-auth-firebase-auth
- Owner: yultyyev
- License: mit
- Created: 2025-11-13T05:45:37.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2025-11-13T07:20:18.000Z (8 months ago)
- Last Synced: 2025-11-13T08:34:03.236Z (8 months ago)
- Topics: authentication, better-auth, firebase, firebase-auth, typescript
- Language: TypeScript
- Homepage:
- Size: 98.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# better-auth-firebase-auth
[](https://www.npmjs.com/package/better-auth-firebase-auth)
[](https://github.com/yultyyev/better-auth-firebase-auth/actions)
[](./LICENSE)
**Firebase Authentication plugin for Better Auth.** Integrate Firebase Auth with Better Auth, allowing users to authenticate using Firebase Auth and create Better Auth sessions.
- **Install:** `pnpm add better-auth-firebase-auth firebase-admin firebase better-auth`
## Why Firebase Auth?
Firebase Authentication provides several advantages when integrated with Better Auth:
- **🔥 Built-in Email Service** - Password reset emails, email verification, and account management emails work out of the box. No need to set up SendGrid, Resend, or other email providers.
- **🌍 Global Infrastructure** - Firebase Auth is backed by Google's infrastructure, ensuring high availability and low latency worldwide.
- **🔐 Battle-Tested Security** - Industry-standard OAuth flows and security best practices built-in.
- **📱 Multi-Platform SDKs** - Consistent authentication across web, iOS, and Android applications.
- **🎨 Customizable Email Templates** - Easily customize email templates directly in the Firebase Console.
- **🚀 Quick Setup** - Get authentication working in minutes without managing your own auth infrastructure.
**Use Case:** Perfect for applications that want robust authentication with email functionality without the complexity of setting up and maintaining email infrastructure.
---
## Installation
# npm
```bash
npm install better-auth-firebase-auth firebase-admin firebase better-auth
```
# pnpm
```bash
pnpm add better-auth-firebase-auth firebase-admin firebase better-auth
```
# yarn
```bash
yarn add better-auth-firebase-auth firebase-admin firebase better-auth
```
# bun
```bash
bun add better-auth-firebase-auth firebase-admin firebase better-auth
```
## Better Auth Compatibility
This package supports both older and newer Better Auth releases for hook middleware imports:
- **Preferred in Better Auth v1.5+:** `createAuthMiddleware` from `better-auth/api`
- **Legacy in older releases:** `createAuthMiddleware` from `better-auth/plugins`
To keep integration stable across versions, this plugin resolves `createAuthMiddleware` from `better-auth/api` first and falls back to `better-auth/plugins` when needed.
If you are writing your own Better Auth plugin code, prefer:
```ts
import { createAuthMiddleware } from "better-auth/api";
```
## Import Paths
To prevent bundling issues where client-side code tries to include server-side dependencies (like `firebase-admin`), the package provides separate export paths:
### Client-side (React components, browser code)
```ts
import { firebaseAuthClientPlugin } from "better-auth-firebase-auth/client";
```
Use this import in client components, browser-only code, or anywhere the code will run in the browser. This ensures bundlers don't try to include `firebase-admin`.
### Server-side (API routes, server components)
```ts
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
```
Use this import in API routes, server-side code, or server components where Node.js is available.
### Main export (backward compatibility)
```ts
import { firebaseAuthPlugin, firebaseAuthClientPlugin } from "better-auth-firebase-auth";
```
The main entry point still exports both plugins for backward compatibility, but using the specific paths above is recommended to avoid bundling issues.
## Features
- ✅ Client-side and server-side token generation modes
- ✅ Optional override of Better Auth's built-in email/password flow
- ✅ Password reset functionality with email verification
- ✅ Server-side only mode (hidden endpoints, all auth through hooks)
- ✅ Sign in with Google
- ✅ Sign in with email/password
- ✅ Full TypeScript support
## Supported Authentication Methods
This plugin currently supports the following Firebase Authentication methods:
### ✅ Currently Supported
- **Google Sign-In** - OAuth provider (`signInWithGoogle`)
- **Email/Password** - Email-based authentication (`signInWithEmail`)
- Sign up with email/password
- Sign in with email/password
- Password reset flow with email verification
- Custom reset URLs
### ❌ Not Yet Supported
The following Firebase Auth providers are available in Firebase but not yet implemented in this plugin:
**Social Providers:**
- Facebook
- GitHub
- Twitter/X
- Microsoft
- Apple
- Yahoo
- LinkedIn
**Phone Authentication:**
- Phone number sign-in with SMS verification
- Multi-factor authentication (MFA)
**Other Methods:**
- Anonymous authentication
- Custom authentication tokens
- SAML/OpenID Connect providers
- Game Center (iOS)
- Play Games (Android)
**Note:** You can still use these providers directly with the Firebase Auth SDK in your application, but they won't automatically create Better Auth sessions. Contributions to add support for additional providers are welcome! See the [Contributing](#contributing) section.
## Usage
### Client-side token generation (default)
**Server-side setup (API routes, `lib/auth.ts`):**
```ts
import { betterAuth } from "better-auth";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
import { getAuth } from "firebase-admin/auth";
export const auth = betterAuth({
plugins: [
firebaseAuthPlugin({
useClientSideTokens: true, // Client generates Firebase tokens
firebaseAdminAuth: getAuth(), // Firebase Admin SDK instance
}),
],
});
```
**Client-side setup (React components, `lib/auth-client.ts`):**
```ts
import { createAuthClient } from "better-auth/react";
import { firebaseAuthClientPlugin } from "better-auth-firebase-auth/client";
export const authClient = createAuthClient({
plugins: [
firebaseAuthClientPlugin({
// Optional: Add Firebase client config for additional features
}),
],
});
```
### Server-side token generation
**Server-side setup (API routes, `lib/auth.ts`):**
```ts
import { betterAuth } from "better-auth";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
import { getAuth } from "firebase-admin/auth";
import type { FirebaseOptions } from "firebase/app";
const firebaseConfig: FirebaseOptions = {
apiKey: process.env.FIREBASE_API_KEY!,
authDomain: process.env.FIREBASE_AUTH_DOMAIN!,
projectId: process.env.FIREBASE_PROJECT_ID!,
};
export const auth = betterAuth({
plugins: [
firebaseAuthPlugin({
useClientSideTokens: false, // Server handles Firebase Auth
firebaseAdminAuth: getAuth(),
firebaseConfig, // Required for server-side mode
}),
],
});
```
**Client-side setup (React components, `lib/auth-client.ts`):**
```ts
import { createAuthClient } from "better-auth/react";
import { firebaseAuthClientPlugin } from "better-auth-firebase-auth/client";
export const authClient = createAuthClient({
plugins: [
firebaseAuthClientPlugin({
// No Firebase config needed - server handles everything
}),
],
});
```
## Password Reset
### Firebase Console Setup (Required)
Before using password reset, configure your Firebase project:
#### 1. Enable Email/Password Authentication
- Go to [Firebase Console](https://console.firebase.google.com/)
- Select your project → **Authentication** → **Sign-in method**
- Enable **Email/Password** provider
- Click **Save**
#### 2. Add Authorized Domains (CRITICAL for Custom URLs)
- Go to **Authentication** → **Settings** → **Authorized domains**
- Add your application domains:
- Development: `localhost` (already included by default)
- Production: `yourdomain.com`, `www.yourdomain.com`
- ⚠️ **Important**: Any domain used in `passwordResetUrl` MUST be in this list, or Firebase will reject the request
#### 3. Customize Email Template (Optional)
- Go to **Authentication** → **Templates** → **Password reset**
- Customize the email subject, body, and sender name
- The email will contain a link to your `passwordResetUrl` with the reset code
### Plugin Configuration
```ts
import { betterAuth } from "better-auth";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
export const auth = betterAuth({
plugins: [
firebaseAuthPlugin({
firebaseConfig: {
apiKey: process.env.FIREBASE_API_KEY!,
authDomain: process.env.FIREBASE_AUTH_DOMAIN!,
projectId: process.env.FIREBASE_PROJECT_ID!,
},
passwordResetUrl: "https://myapp.com/reset-password", // Your custom reset page
// OR omit passwordResetUrl to use Firebase's default URL
}),
],
});
```
**Note**: If `passwordResetUrl` is not provided, Firebase uses its default URL (`https://YOUR_PROJECT.firebaseapp.com/__/auth/action`), which works without any additional setup but doesn't match your app's branding.
### Password Reset Flow
#### Step 1: Request Password Reset
```typescript
await authClient.sendPasswordReset({
email: "user@example.com"
});
// User receives email with link like: https://myapp.com/reset-password?oobCode=ABC123&mode=resetPassword
```
#### Step 2: Extract Code from URL
On your reset password page (`/reset-password`):
```typescript
import { extractOobCodeFromUrl } from "better-auth-firebase-auth/client";
// Extracts oobCode from current URL query parameters
const oobCode = extractOobCodeFromUrl();
if (!oobCode) {
// Show error: Invalid or missing reset code
return;
}
```
#### Step 3: Verify Reset Code (Optional but Recommended)
```typescript
try {
const { valid, email } = await authClient.verifyPasswordResetCode({
oobCode
});
// Show reset form with email pre-filled
console.log("Reset password for:", email);
} catch (error) {
// Show error: Invalid or expired reset code
}
```
#### Step 4: Confirm New Password
```typescript
try {
await authClient.confirmPasswordReset({
oobCode,
newPassword: "newSecurePassword123",
});
// Success! Redirect to login page
} catch (error) {
// Show error: Failed to reset password
}
```
### Complete Example
```tsx
// app/reset-password/page.tsx
"use client";
import { useState, useEffect } from "react";
import { authClient } from "@/lib/auth-client";
import { extractOobCodeFromUrl } from "better-auth-firebase-auth/client";
export default function ResetPasswordPage() {
const [oobCode, setOobCode] = useState(null);
const [email, setEmail] = useState("");
const [newPassword, setNewPassword] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
useEffect(() => {
const code = extractOobCodeFromUrl();
if (!code) {
setError("Invalid or missing reset code");
return;
}
setOobCode(code);
// Verify the code
authClient.verifyPasswordResetCode({ oobCode: code })
.then(({ email }) => setEmail(email))
.catch(() => setError("Invalid or expired reset code"));
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!oobCode) return;
try {
await authClient.confirmPasswordReset({
oobCode,
newPassword,
});
setSuccess(true);
} catch (err) {
setError("Failed to reset password");
}
};
if (error) return
Error: {error};
if (success) return Password reset successful! Login
;
return (
Reset Password
Email: {email}
setNewPassword(e.target.value)}
required
/>
Reset Password
);
}
```
### Troubleshooting
**Error: "Invalid action code"**
- The reset link has expired (default: 1 hour)
- The code has already been used
- Solution: Request a new password reset email
**Error: "Unauthorized domain"**
- Your `passwordResetUrl` domain is not in Firebase's authorized domains list
- Solution: Add the domain in Firebase Console → Authentication → Settings → Authorized domains
**Email not received**
- Check spam/junk folder
- Verify the email address is registered in Firebase Auth
- Check Firebase Console → Authentication → Templates for email settings
## Options
```ts
firebaseAuthPlugin({
useClientSideTokens?: boolean; // Default: true
overrideEmailPasswordFlow?: boolean; // Default: false
serverSideOnly?: boolean; // Default: false
firebaseAdminAuth?: admin.auth.Auth; // Optional
firebaseConfig?: FirebaseOptions; // Required for server-side mode
passwordResetUrl?: string; // Custom URL for password reset page
sessionExpiresInDays?: number; // Default: 7
});
```
## Example
See the [minimal example](./examples/minimal) for a complete Next.js setup demonstrating the plugin usage. That README also explains **build-time defaults** in `lib/auth.ts` (placeholder secret and optional Firebase env) so `next build` can run without a full `.env`.
## FAQ
### What is `better-auth-firebase-auth`?
`better-auth-firebase-auth` is a Better Auth plugin that connects Firebase Authentication to Better Auth sessions. It lets you use Firebase sign-in flows while still using Better Auth for session management and app-level auth features.
### Does this plugin support Google Sign-In and email/password authentication?
Yes. The plugin supports Google Sign-In and email/password authentication, including password reset endpoints and helpers. Additional Firebase providers (such as GitHub, Apple, phone auth, and MFA) are not yet implemented in this package.
### How is this different from using Firebase Auth alone?
Firebase Auth handles identity (who the user is), while this plugin bridges Firebase identities into Better Auth users, accounts, and sessions. This is useful when your app already uses Better Auth and you want Firebase providers and Firebase-managed email flows.
### Should I use client-side or server-side token generation?
Use client-side token generation (`useClientSideTokens: true`) for the simplest setup. Use server-side token generation (`useClientSideTokens: false`) when you want the server to handle Firebase client initialization and token exchange logic.
### Can I use this package in a Next.js app?
Yes. The package is designed for modern TypeScript apps and works well with Next.js. Use `better-auth-firebase-auth/server` in server code and `better-auth-firebase-auth/client` in browser/client code to avoid bundling issues.
### Does this plugin override Better Auth email/password by default?
No. `overrideEmailPasswordFlow` is `false` by default. You can opt in to override Better Auth email/password routes when you want Firebase to be the source of truth for those credentials.
## Firestore Adapter
For storing Better Auth data in Firestore, see [@yultyyev/better-auth-firestore](https://www.npmjs.com/package/@yultyyev/better-auth-firestore):
```bash
npm install @yultyyev/better-auth-firestore
```
```ts
import { firestoreAdapter } from "@yultyyev/better-auth-firestore";
export const auth = betterAuth({
database: firestoreAdapter(),
plugins: [firebaseAuthPlugin({ ... })],
});
```
## Contributing
Contributions are welcome! Please follow the [Better Auth Contributing Guide](https://www.better-auth.com/docs/reference/contributing) for development setup and code style.
## License
MIT