Using Firebase with Chrome Extensions: Authentication, Database, and Hosting

18 min read

Using Firebase with Chrome Extensions: Authentication, Database, and Hosting

Using Firebase with Chrome Extensions: Authentication, Database, and Hosting

Building a Chrome extension that requires user accounts, persistent data storage, or server-side logic can be challenging. While Chrome extensions run entirely in the browser, many real-world applications need a backend to store user data, handle authentication, and synchronize information across devices. This is where Firebase comes in — a powerful Backend-as-a-Service (BaaS) platform that integrates seamlessly with Chrome extensions.

In this comprehensive guide, we will explore how to use Firebase with Chrome extensions to add authentication, database (Firestore), and hosting capabilities. Whether you are building a note-taking extension, a productivity tool, or a team collaboration app, Firebase provides the backend infrastructure you need without requiring you to set up and manage your own servers.


Why Use Firebase with Chrome Extensions?

Firebase offers several advantages that make it an ideal backend choice for Chrome extensions:

1. Serverless Architecture

Firebase eliminates the need to set up and maintain backend servers. All the server-side logic is handled by Google’s infrastructure, which means you can focus on building your extension’s frontend while Firebase handles the heavy lifting.

2. Real-time Database

Firestore provides real-time synchronization capabilities, which is perfect for Chrome extensions that need to share data across multiple devices or between different parts of your extension (popup, background script, content scripts).

3. Secure Authentication

Firebase Authentication supports multiple authentication methods including email/password, Google, Facebook, GitHub, and more. You get secure authentication out of the box without implementing your own identity management system.

4. Generous Free Tier

Firebase’s Spark plan offers a generous free tier that includes authentication, Firestore database, and hosting. This makes it perfect for side projects and small-to-medium extensions.

5. Easy Integration with Chrome Extensions

Firebase provides SDKs that work well within Chrome extension environments. With proper configuration, you can use Firebase services directly from your extension’s popup, background scripts, and content scripts.


Setting Up Firebase for Your Chrome Extension

Before integrating Firebase into your Chrome extension, you need to create a Firebase project and configure it for extension use.

Step 1: Create a Firebase Project

  1. Go to the Firebase Console
  2. Click “Add project” and follow the setup wizard
  3. Give your project a name (e.g., “my-extension-backend”)
  4. Disable Google Analytics (optional, saves resources)
  5. Click “Create project”

Step 2: Register Your Chrome Extension

After creating your Firebase project:

  1. In the Firebase Console, click the gear icon ⚙️ next to “Project Overview”
  2. Select “Your apps” → “Add app” → Web (</>)
  3. Register your app with a nickname (e.g., “Chrome Extension”)
  4. Important: Do NOT copy the firebaseConfig code yet — we will generate it specifically for extension use

Step 3: Configure Firebase for Chrome Extension

Chrome extensions run in a unique environment with specific security requirements. You need to configure Firebase properly:

  1. In Firebase Console, go to Project Settings
  2. Under “Your apps”, select your web app
  3. Look for the firebaseConfig object — you will need these values:
    • apiKey
    • authDomain
    • projectId
    • storageBucket
    • messagingSenderId
    • appId

Step 4: Update Your Manifest.json

Your Chrome extension needs the correct permissions and host permissions to communicate with Firebase:

{
  "manifest_version": 3,
  "name": "My Firebase Extension",
  "version": "1.0",
  "permissions": [
    "activeTab"
  ],
  "host_permissions": [
    "https://*.firebaseio.com",
    "https://*.googleapis.com"
  ],
  "background": {
    "service_worker": "background.js"
  }
}

The host permissions are critical — without them, your extension cannot make requests to Firebase servers.


Firebase Authentication in Chrome Extensions

Firebase Authentication allows users to sign in to your Chrome extension using various methods. Let’s implement email/password authentication as a starting point.

Installing the Firebase SDK

First, install Firebase in your extension project:

npm install firebase

Setting Up Authentication

Create an authentication module in your extension:

// firebase-config.js
import { initializeApp } from 'firebase/app';
import { getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, onAuthStateChanged } from 'firebase/auth';

// Your Firebase configuration
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_PROJECT_ID.appspot.com",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID"
};

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

// Export authentication functions
export { auth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, onAuthStateChanged };

Creating a Login UI

In your extension’s popup HTML:

<!DOCTYPE html>
<html>
<head>
  <style>
    body { width: 300px; padding: 20px; font-family: sans-serif; }
    input { width: 100%; padding: 8px; margin: 5px 0; box-sizing: border-box; }
    button { width: 100%; padding: 10px; margin: 5px 0; cursor: pointer; }
    .error { color: red; font-size: 12px; }
  </style>
</head>
<body>
  <h2>Sign In</h2>
  <input type="email" id="email" placeholder="Email">
  <input type="password" id="password" placeholder="Password">
  <button id="loginBtn">Login</button>
  <button id="registerBtn">Register</button>
  <p class="error" id="error"></p>
  <div id="userInfo" style="display:none;">
    <p>Signed in as: <span id="userEmail"></span></p>
    <button id="logoutBtn">Logout</button>
  </div>
  <script type="module" src="popup.js"></script>
</body>
</html>

Handling Authentication in Popup

// popup.js
import { auth, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut, onAuthStateChanged } from './firebase-config.js';

const emailInput = document.getElementById('email');
const passwordInput = document.getElementById('password');
const loginBtn = document.getElementById('loginBtn');
const registerBtn = document.getElementById('registerBtn');
const logoutBtn = document.getElementById('logoutBtn');
const errorEl = document.getElementById('error');
const userInfoEl = document.getElementById('userInfo');
const userEmailEl = document.getElementById('userEmail');

// Check auth state on load
onAuthStateChanged(auth, (user) => {
  if (user) {
    showUserInfo(user);
  } else {
    showLoginForm();
  }
});

// Login handler
loginBtn.addEventListener('click', async () => {
  try {
    errorEl.textContent = '';
    await signInWithEmailAndPassword(auth, emailInput.value, passwordInput.value);
  } catch (error) {
    errorEl.textContent = error.message;
  }
});

// Register handler
registerBtn.addEventListener('click', async () => {
  try {
    errorEl.textContent = '';
    await createUserWithEmailAndPassword(auth, emailInput.value, passwordInput.value);
  } catch (error) {
    errorEl.textContent = error.message;
  }
});

// Logout handler
logoutBtn.addEventListener('click', async () => {
  await signOut(auth);
  showLoginForm();
});

function showUserInfo(user) {
  document.querySelector('h2').textContent = 'Dashboard';
  document.querySelectorAll('input, button').forEach(el => {
    if (el.id !== 'logoutBtn') el.style.display = 'none';
  });
  userInfoEl.style.display = 'block';
  userEmailEl.textContent = user.email;
}

function showLoginForm() {
  document.querySelector('h2').textContent = 'Sign In';
  document.querySelectorAll('input, button').forEach(el => el.style.display = 'block');
  userInfoEl.style.display = 'none';
}

Firebase Auth Chrome Extension Best Practices

When implementing Firebase Authentication in Chrome extensions, consider these best practices:

  1. Use Chrome Identity API for OAuth: For Google, Facebook, or other OAuth providers, use Chrome’s identity API instead of Firebase’s popup-based OAuth. This provides a better user experience.

  2. Secure Your Extension: Always verify authentication state server-side when making database requests.

  3. Persist Authentication: Firebase Auth automatically persists auth state, but you should handle token refresh gracefully.

  4. Use Background Scripts for Auth: Keep authentication logic in your background script to share auth state across popup, content scripts, and other parts of your extension.


Firestore Database in Chrome Extensions

Firestore is Firebase’s flexible, scalable NoSQL cloud database. It is perfect for storing user data, settings, and application state for your Chrome extension.

Setting Up Firestore

Import and initialize Firestore:

// firebase-firestore.js
import { initializeApp } from 'firebase/app';
import { getFirestore, collection, doc, setDoc, getDoc, getDocs, updateDoc, deleteDoc, query, where, orderBy, onSnapshot } from 'firebase/firestore';

const firebaseConfig = {
  // Your config here
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

export { db, collection, doc, setDoc, getDoc, getDocs, updateDoc, deleteDoc, query, where, orderBy, onSnapshot };

Creating and Reading Data

// example-usage.js
import { db, collection, doc, setDoc, getDoc, getDocs, query, where, onSnapshot } from './firebase-firestore.js';
import { auth } from './firebase-config.js';

// Create a user profile
async function createUserProfile(userId, data) {
  const userRef = doc(db, 'users', userId);
  await setDoc(userRef, {
    ...data,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString()
  });
}

// Read user profile
async function getUserProfile(userId) {
  const userRef = doc(db, 'users', userId);
  const snapshot = await getDoc(userRef);
  return snapshot.exists() ? snapshot.data() : null;
}

// Get user's notes
async function getUserNotes(userId) {
  const notesRef = collection(db, 'notes');
  const q = query(notesRef, where('userId', '==', userId), orderBy('createdAt', 'desc'));
  const snapshot = await getDocs(q);
  return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
}

// Real-time listener for notes
function subscribeToNotes(userId, callback) {
  const notesRef = collection(db, 'notes');
  const q = query(notesRef, where('userId', '==', userId), orderBy('createdAt', 'desc'));
  return onSnapshot(q, (snapshot) => {
    const notes = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
    callback(notes);
  });
}

Updating and Deleting Data

// Update a note
async function updateNote(noteId, data) {
  const noteRef = doc(db, 'notes', noteId);
  await updateDoc(noteRef, {
    ...data,
    updatedAt: new Date().toISOString()
  });
}

// Delete a note
async function deleteNote(noteId) {
  const noteRef = doc(db, 'notes', noteId);
  await deleteDoc(noteRef);
}

Firestore Chrome Extension Security Rules

Secure your Firestore data with proper security rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // User can only read/write their own data
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
    
    match /notes/{noteId} {
      allow read, write: if request.auth != null && request.auth.uid == resource.data.userId;
      allow create: if request.auth != null && request.auth.uid == request.resource.data.userId;
    }
  }
}

Firestore Chrome Extension Best Practices

  1. Use Composite Indexes: Complex queries require Firestore indexes — check the console for index creation links when queries fail.

  2. Optimize Reads: Use real-time listeners sparingly and unsubscribe when not needed to avoid unnecessary reads.

  3. Structure Data Denormalized: Firestore works best with denormalized data structures. Store data where you read it.

  4. Implement Offline Support: Firestore SDK includes offline persistence — enable it for better user experience.


Firebase Hosting for Chrome Extensions

While Chrome extensions run locally in the browser, Firebase Hosting can serve your extension’s web components, documentation, and landing pages.

Setting Up Firebase Hosting

  1. Install Firebase CLI:
    npm install -g firebase-tools
    
  2. Initialize Firebase in your project:
    firebase init hosting
    
  3. Select your Firebase project when prompted

  4. Configure your public directory (e.g., “public” or “docs”)

  5. Configure as a single-page app: Yes (if using SPA routing)

Deploying Your Extension’s Website

If your extension includes a website (landing page, documentation, dashboard), deploy it with:

firebase deploy --only hosting

Your site will be available at https://your-project.web.app

Using Hosting with Chrome Extension

Many extensions use Firebase Hosting to serve:

  • Landing pages: Market your extension with a professional website
  • Documentation: Host detailed guides and tutorials
  • Dashboard: Create a web-based dashboard that complements your extension
  • Privacy Policy: Required for Chrome Web Store compliance

Connecting Content Scripts to Firebase

Content scripts run in the context of web pages, making Firebase integration slightly different. Here is how to connect:

Option 1: Message Passing

The recommended approach is to communicate between your content script and background/service worker:

// content-script.js
// Request data from background script
chrome.runtime.sendMessage({ type: 'GET_USER_DATA' }, (response) => {
  console.log('User data:', response.data);
});

// Background script
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'GET_USER_DATA') {
    // Get data from Firestore
    getUserProfile(message.userId).then(data => {
      sendResponse({ data });
    });
    return true; // Keep channel open for async response
  }
});

Option 2: Direct Connection (Advanced)

For complex use cases, you can inject Firebase SDK directly into pages, but this requires careful security considerations:

// Only recommended for trusted pages
// content-script.js (manifest V3)
{
  "content_scripts": [{
    "matches": ["https://your-trusted-app.com/*"],
    "js": ["firebase-content.js"]
  }]
}

Advanced Patterns and Tips

Using Firebase with Manifest V3 Service Workers

Service workers in Manifest V3 have some limitations. Here are tips for working with Firebase:

  1. Use Modular SDK: Import only what you need to reduce bundle size
  2. Handle Caching: Service workers may be terminated — save state appropriately
  3. Use Background Context: Initialize Firebase in the background script context

Syncing Extension State

Use Firestore to sync state across devices:

// Sync user preferences across devices
async function syncPreferences(userId, preferences) {
  const prefRef = doc(db, 'preferences', userId);
  await setDoc(prefRef, preferences, { merge: true });
}

// Listen for changes from other devices
function subscribeToPreferences(userId, callback) {
  const prefRef = doc(db, 'preferences', userId);
  return onSnapshot(prefRef, (snapshot) => {
    if (snapshot.exists()) {
      callback(snapshot.data());
    }
  });
}

Offline Support

Enable Firestore offline persistence for better experience:

import { enableIndexedDbPersistence } from 'firebase/firestore';

enableIndexedDbPersistence(db)
  .catch((err) => {
    if (err.code == 'failed-precondition') {
      // Multiple tabs open, persistence can only be enabled in one tab at a time
    } else if (err.code == 'unimplemented') {
      // Current browser does not support all of the features required to enable persistence
    }
  });

Conclusion

Firebase provides a powerful, serverless backend solution for Chrome extensions. With Firebase Authentication, you can implement secure user login without building your own identity system. Firestore offers real-time, scalable database capabilities perfect for storing user data, settings, and application state. Firebase Hosting rounds out the package by providing a way to deploy landing pages, documentation, and web dashboards for your extension.

The key to successful Firebase integration with Chrome extensions lies in understanding the extension’s unique architecture. Use background scripts as the central hub for Firebase communication, implement proper security rules, and leverage Firebase’s real-time capabilities to create a seamless experience across devices.

By combining Chrome extensions’ reach with Firebase’s backend power, you can build sophisticated, data-driven applications that serve millions of users. Start with the basics covered in this guide, then explore more advanced features like Cloud Functions, Analytics, and Cloud Messaging as your extension grows.

Remember to follow Chrome Web Store policies, implement proper privacy notices, and test thoroughly before publishing. With Firebase handling your backend, you can focus on creating an exceptional user experience in your extension.

No previous article
No next article