/lovable-issues

Integrating Firebase Authentication with Lovable

Discover why a manual Firebase integration is key for Lovable projects. Learn step-by-step Firebase Auth setup with expert best practices.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Book a free No-Code consultation

Why Firebase Integration Needs Manual Setup in Lovable

Firebase requires manual setup in Lovable because key Firebase steps must happen outside of app code (in Google/Firebase consoles) and require secure secrets and CLI operations that Lovable’s chat environment can’t run for you. You must create the Firebase project, enable providers/APIs, register OAuth redirect/authorized domains, and provision service-account credentials manually — then supply those values into Lovable’s Secrets UI or a synced GitHub repo. Lovable can edit your app files and add placeholders, but it cannot perform console actions, run the Firebase CLI, or safely retrieve private Google service-account keys for you.

 

Why this is necessary (details)

 

  • Console-only resources: Creating a Firebase project, enabling OAuth providers, setting authorized domains, and enabling APIs are done in the Firebase/GCP web consoles — these aren’t actions you can run from Lovable’s editor.
  • Secrets & security: Admin credentials (service-account JSON, API keys, client secrets) must be kept out of source. Lovable provides a Secrets UI to store these, but you must upload or paste them manually — Lovable won’t fetch them for you.
  • CLI-dependent steps: Initializing functions, deploying rules, and running emulators use firebase/gcloud CLIs. Lovable has no terminal, so those deploys must be done outside Lovable (local machine or CI). Use GitHub export/sync if you need CI-based deploys.
  • Domain/redirect nuance: Auth redirect URIs and authorized domains must match your Lovable preview/published domains. Previews are ephemeral; you’ll often need to add both preview and production domains manually in the Firebase console.
  • Server vs client config: Admin SDKs need private keys server-side (store in Lovable Secrets or external CI secret store), while client SDK needs only public config — you must place these in the right scope yourself.

 

Lovable prompt(s) you can paste to create guidance/checklist inside your project

 

// Please create file docs/FIREBASE_MANUAL_SETUP.md with the exact content below
// This file intentionally explains the manual steps required outside Lovable
# FIREBASE MANUAL SETUP (for Lovable projects)

// 1) Console steps (Firebase/GCP)
// - Create a Firebase project in the Firebase Console.
// - Enable the Authentication providers you need (Email, Google, etc.).
// - Add your Lovable preview domain(s) and published domain to "Authorized domains" and OAuth redirect URIs.
// - If using server-side functions, enable required Google APIs and create a service account with the needed roles.
// - Download the service-account JSON (keep it private).

// 2) What to store in Lovable Secrets UI
// - FIREBASE_API_KEY (public key)
// - FIREBASE_AUTH_DOMAIN
// - FIREBASE_PROJECT_ID
// - FIREBASE_APP_ID
// - FIREBASE_SERVICE_ACCOUNT (paste full service-account JSON here; mark as secret)
// - Any OAuth client secret values (if applicable)

// 3) Deploy notes (outside Lovable)
// - Deploying Firebase Functions or running the Emulator requires the Firebase CLI or gcloud CLI.
// - These steps must be run locally or in CI (use GitHub export/sync for CI deployment).
// - Example: firebase deploy --only functions (run on your machine or CI).
//
// 4) Important reminders
// - Do NOT commit service-account JSON to source control.
// - Ensure authorized domains include both preview and production domains used by Lovable.
// - Use Lovable Secrets UI to add the keys; reference them in code via environment variables or runtime secrets.

 

// Please create file .lovable/firebase-placeholders.md with the exact content below
// This file provides placeholders Lovable can safely keep in repo; replace at runtime via Secrets UI.
# Firebase placeholders for code

// Create a lightweight module or env example to be filled from Secrets UI or CI.
// Do NOT commit real keys here — replace with secret bindings in Lovable.

export const FIREBASE_CONFIG_PLACEHOLDER = {
  // // Replace these with values set in Lovable Secrets UI or GitHub secrets
  apiKey: "FIREBASE_API_KEY_FROM_SECRETS",
  authDomain: "FIREBASE_AUTH_DOMAIN_FROM_SECRETS",
  projectId: "FIREBASE_PROJECT_ID_FROM_SECRETS",
  appId: "FIREBASE_APP_ID_FROM_SECRETS"
};

// For server-side Admin SDK, configure to load FIREBASE_SERVICE_ACCOUNT from Secrets UI.

Still stuck?
Copy this prompt into ChatGPT and get a clear, personalized explanation.

This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.

AI AI Prompt

How to Integrate Firebase Auth with Lovable Projects

Use this prompt first (short summary)

Create a minimal Firebase Auth integration: client SDK init, an AuthContext + hook, Login page, and a simple server API route to verify ID tokens. Store client config and the service-account JSON in Lovable Secrets. Edit these files (paths below). Note: adding npm deps (firebase, firebase-admin) requires GitHub sync / local install — I indicate that step as "outside Lovable (terminal required)".

 

Lovable prompt — Add client Firebase init, AuthContext, and Login page

 

Paste this entire prompt into Lovable chat (Chat Mode). It should create files and update App.tsx.

// Please create the following files and edits in the project.
// Add client Firebase init and an Auth Provider + Login UI.

// Create src/lib/firebaseClient.ts
// This initializes the client Firebase app using Secrets.
// IMPORTANT: use process.env.* values (Lovable Secrets will inject env vars).
export const CLIENT_FIREBASE_INIT = `// src/lib/firebaseClient.ts
import { initializeApp, getApps } from 'firebase/app';
import { getAuth } from 'firebase/auth';

// // Firebase config is read from environment variables injected from Lovable Secrets
const firebaseConfig = {
  apiKey: process.env.FIREBASE_API_KEY,
  authDomain: process.env.FIREBASE_AUTH_DOMAIN,
  projectId: process.env.FIREBASE_PROJECT_ID,
  appId: process.env.FIREBASE_APP_ID,
};

if (!getApps().length) {
  initializeApp(firebaseConfig);
}

export const auth = getAuth();
`;

// Create src/contexts/AuthContext.tsx
export const AUTH_CONTEXT = `// src/contexts/AuthContext.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import { onAuthStateChanged, signInWithPopup, GoogleAuthProvider, signOut } from 'firebase/auth';
import { auth } from '../lib/firebaseClient';

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsub = onAuthStateChanged(auth, async (u) => {
      setUser(u);
      setLoading(false);
    });
    return () => unsub();
  }, []);

  const signInWithGoogle = async () => {
    const provider = new GoogleAuthProvider();
    await signInWithPopup(auth, provider);
  };

  const signOutUser = async () => {
    await signOut(auth);
  };

  return (
    <AuthContext.Provider value={{ user, loading, signInWithGoogle, signOutUser }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);
`;

// Create src/pages/Login.tsx
export const LOGIN_PAGE = `// src/pages/Login.tsx
import React from 'react';
import { useAuth } from '../contexts/AuthContext';

export default function LoginPage() {
  const { signInWithGoogle, loading } = useAuth();

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Sign in</h1>
      <button onClick={signInWithGoogle}>Sign in with Google</button>
    </div>
  );
}
`;

// Update src/App.tsx to wrap routes with AuthProvider (replace <App/> root as needed)
export const APP_UPDATE = `// src/App.tsx
// Update this file: wrap your app with AuthProvider so authentication state is available.
import React from 'react';
import { AuthProvider } from './contexts/AuthContext';
import Routes from './Routes'; // // adjust if your routes live elsewhere

export default function App() {
  return (
    <AuthProvider>
      <Routes />
    </AuthProvider>
  );
}
`;

// Instruction to Lovable: create files and update App.tsx exactly as above.
Please create the three new files and update src/App.tsx with the provided content. Use the existing routing file name if different but ensure AuthProvider wraps the app root.

 

Lovable prompt — Set Secrets in Lovable UI

 

Paste this into Lovable chat to instruct the Secrets UI actions.

// Please add these Secrets in Lovable Cloud > Secrets (exact keys below).
// Insert your Firebase web app values into the Secrets UI fields.

Please add:
- FIREBASE_API_KEY = <your Firebase web apiKey>
- FIREBASE_AUTH_DOMAIN = <your Firebase authDomain>
- FIREBASE_PROJECT_ID = <your Firebase projectId>
- FIREBASE_APP_ID = <your Firebase appId>

Also add a service account JSON for server verification:
- FIREBASE_SERVICE_ACCOUNT = <full JSON string of service account key>

Mark secrets as protected/secret.

 

Lovable prompt — Add server API to verify ID tokens (requires firebase-admin)

 

Paste into Lovable chat. Note: installing firebase-admin must be done via GitHub sync/local install; I mark that step.

// Create a server API route to verify Firebase ID tokens for protected server endpoints.
// Create file: src/pages/api/auth/verifyToken.ts (or /api/auth/verify.ts depending on your framework)

export const VERIFY_API = `// src/pages/api/auth/verifyToken.ts
// // Serverless API that verifies Firebase ID token from Authorization header
import type { NextApiRequest, NextApiResponse } from 'next';
import admin from 'firebase-admin';

// Initialize admin using service account from env (SERVICE_ACCOUNT is JSON string)
if (!admin.apps.length) {
  const svc = JSON.parse(process.env.FIREBASE_SERVICE_ACCOUNT || '{}');
  admin.initializeApp({
    credential: admin.credential.cert(svc),
  });
}

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const authHeader = req.headers.authorization || '';
  const token = authHeader.replace('Bearer ', '');
  if (!token) return res.status(401).json({ error: 'Missing token' });

  try {
    const decoded = await admin.auth().verifyIdToken(token);
    return res.status(200).json({ uid: decoded.uid, decoded });
  } catch (err) {
    return res.status(401).json({ error: 'Invalid token' });
  }
}
`;

// Create the file with the content above.

Please create src/pages/api/auth/verifyToken.ts with that content.

 

Outside Lovable (terminal required) — Add dependencies and deploy

 

  • After you commit/sync to GitHub, run npm/yarn install to add dependencies: firebase and firebase-admin.
  • Dependency names: firebase, firebase-admin.
  • Reason: Lovable cannot run npm install inside the web UI — sync to GitHub and run installs in your CI or locally, then push.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Book a Free Consultation

Best Practices for Using Firebase Auth in Lovable

Use Lovable Secrets for any sensitive values, keep only public keys in client code, centralize Firebase client init (read env vars), add a single AuthProvider + useAuth hook that listens to onIdTokenChanged and periodically refreshes the token, protect routes with a requireAuth wrapper, and never commit service-account secrets — for any server-side ID-token verification use a server-only endpoint (implement in repo via Lovable edits) but export to GitHub and deploy outside Lovable if you need to run firebase-admin or install server dependencies.

 

Lovable prompts to implement these best practices

 

// Paste this into Lovable chat to create a secure client init and README instructions.
// Create file src/lib/firebaseClient.ts
// and update README.md with Secrets UI instructions.

Please create a new file at src/lib/firebaseClient.ts with this content:

// initialize Firebase client using environment variables
import { initializeApp, getApps } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

if (!getApps().length) {
  initializeApp(firebaseConfig);
}

export const auth = getAuth();

Also update README.md (or create README.md) with a "Secrets" section that instructs:
- Add the client keys above via Lovable's Secrets UI as NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, etc.
- Do NOT commit service account JSON. If you need server verification, store service account JSON in Lovable Secrets as FIREBASE_ADMIN_SA (JSON) and follow the separate server deployment note.

 

// Paste this into Lovable chat to add an AuthProvider and hook.
// Create src/hooks/useAuth.tsx and src/components/AuthProvider.tsx
// Update src/pages/_app.tsx (or src/App.tsx) to wrap the app with <AuthProvider>.

Please create src/hooks/useAuth.tsx:

import React, { useEffect, useState, useContext, createContext } from "react";
import { onIdTokenChanged, User } from "firebase/auth";
import { auth } from "../lib/firebaseClient";

type AuthContextValue = { user: User | null; token: string | null; loading: boolean };

const AuthContext = createContext<AuthContextValue>({ user: null, token: null, loading: true });

export function useAuth() {
  return useContext(AuthContext);
}

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [token, setToken] = useState<string | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    let refreshInterval: number | undefined;

    const unsubscribe = onIdTokenChanged(auth, async (u) => {
      setUser(u ?? null);
      if (u) {
        const t = await u.getIdToken();
        setToken(t);
        // refresh token every 45 minutes while logged in
        refreshInterval = window.setInterval(async () => {
          const fresh = await u.getIdToken(true);
          setToken(fresh);
        }, 45 * 60 * 1000);
      } else {
        setToken(null);
        if (refreshInterval) clearInterval(refreshInterval);
      }
      setLoading(false);
    });

    return () => {
      unsubscribe();
      if (refreshInterval) clearInterval(refreshInterval);
    };
  }, []);

  return <AuthContext.Provider value={{ user, token, loading }}>{children}</AuthContext.Provider>;
}

Then update src/pages/_app.tsx (or src/App.tsx) to wrap the app:

// inside _app.tsx or App.tsx
import { AuthProvider } from "../hooks/useAuth";

function MyApp({ Component, pageProps }) {
  return (
    <AuthProvider>
      <Component {...pageProps} />
    </AuthProvider>
  );
}

export default MyApp;

 

// Paste this into Lovable chat to add a route protection helper.
// Create src/lib/requireAuth.tsx and show how to use it in a page file.

Please create src/lib/requireAuth.tsx:

import React from "react";
import { useRouter } from "next/router";
import { useAuth } from "../hooks/useAuth";

export function RequireAuth({ children }: { children: React.ReactNode }) {
  const { user, loading } = useAuth();
  const router = useRouter();

  React.useEffect(() => {
    if (!loading && !user) {
      router.replace("/login");
    }
  }, [user, loading]);

  if (loading || !user) return <div>Loading...</div>;
  return <>{children}</>;
}

Usage example for a page (edit pages/protected.tsx):

// wrap page export default function ProtectedPage() { return (<RequireAuth>...page...</RequireAuth>) }

 

Notes about server-side ID token verification and secrets (one important caveat)

 

  • Never commit Firebase admin/service-account JSON to the repo. Put it in Lovable Secrets as FIREBASE_ADMIN_SA (JSON string) and reference process.env.FIREBASE_ADMIN_SA in server-only code.
  • If you create a server endpoint that uses firebase-admin (for verifying ID tokens), adding the server file via Lovable is fine, but installing firebase-admin and deploying server-side runtime may require exporting to GitHub and running npm install / deploy in your target environment. Label any deploy/install steps as outside Lovable (terminal required).
  • Use Preview to test client auth flows in Lovable, and use Publish/GitHub sync to push server code for CI/deploy.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022