Firebase Google sign-in with Vue 3 and Nuxt
For Vue 3, install VueFire with its VueFireAuth() module and use useFirebaseAuth() plus useCurrentUser() in components; for Nuxt, use the VueFire Nuxt module (or a .client plugin) so Firebase Auth only runs in the browser.
To make Google's screen show your domain on a Nuxt server deployment, add a routeRules proxy from /__/auth/** to YOUR-PROJECT.firebaseapp.com and set authDomain to your domain.
Why Google sign-in fails in Vue and Nuxt apps
- Nuxt renders on the server first. VueFire's docs say
useFirebaseAuth()isnullon the server, so a sign-in call that runs during SSR (insetupat top level, for example) fails. Popup sign-in belongs in a click handler. - "No user" vs. "not loaded yet".
useCurrentUser()isundefineduntil Firebase has restored the session, thennullor a user. Treatingundefinedas signed out causes flicker and wrong redirects. - Route guards that run too early. VueFire asks you to register the auth-aware guard before
app.use(router)so the first navigation waits for the user. - Unlisted hosts. Nuxt's dev server runs at
http://localhost:3000; a plain Vue + Vite app atlocalhost:5173. Projects created after April 28, 2025 don't getlocalhostas an authorized domain by default. - Redirect sign-in. Firebase says
signInWithRedirect()needs one of its workarounds on Chrome M115+ (from June 24, 2024), Firefox 109+ and Safari 16.1+.
Step-by-step fix: Vue 3 (Vite) with VueFire
Install the packages:
npm i vuefire firebase
Register VueFire with the Auth module:
// src/main.ts
import { createApp } from 'vue';
import { initializeApp } from 'firebase/app';
import { VueFire, VueFireAuth, getCurrentUser } from 'vuefire';
import App from './App.vue';
import router from './router';
const firebaseApp = initializeApp({
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
});
const app = createApp(App);
app.use(VueFire, { firebaseApp, modules: [VueFireAuth()] });
// Add the guard before app.use(router) so the first navigation is covered
router.beforeEach(async (to) => {
if (to.meta.requiresAuth) {
const user = await getCurrentUser();
if (!user) return { path: '/login', query: { redirect: to.fullPath } };
}
});
app.use(router);
app.mount('#app');
Use the composables in a component:
<!-- src/components/GoogleSignIn.vue -->
<script setup lang="ts">
import { GoogleAuthProvider, signInWithPopup, signOut } from 'firebase/auth';
import { useCurrentUser, useFirebaseAuth } from 'vuefire';
const auth = useFirebaseAuth(); // null during server rendering in Nuxt
const user = useCurrentUser(); // undefined until loaded, then User or null
const provider = new GoogleAuthProvider();
function signIn() {
signInWithPopup(auth!, provider).catch((reason) => {
console.error('Google sign-in failed', reason);
});
}
</script>
<template>
<span v-if="user === undefined">Loading…</span>
<button v-else-if="user" @click="signOut(auth!)">Sign out {{ user.displayName }}</button>
<button v-else @click="signIn">Sign in with Google</button>
</template>
If you'd rather not add VueFire, the same pattern works with a hand-written composable: call onAuthStateChanged() once in a module, store the user in a ref, and return it from useAuthUser().
Step-by-step fix: Nuxt with the VueFire module
Install it:
npm install firebase
npx nuxi@latest module add vuefire
Configure it in nuxt.config.ts:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-vuefire'],
vuefire: {
auth: { enabled: true },
config: {
apiKey: 'your-web-api-key',
authDomain: 'YOUR-PROJECT.firebaseapp.com', // switch to your domain once /__/auth is proxied (see below)
projectId: 'YOUR-PROJECT',
appId: '1:000000000000:web:abc123',
},
},
});
Firebase says API keys restricted to Firebase services don't need to be secret, so these values can live in the config. The GoogleSignIn.vue component above works unchanged in Nuxt. Protect pages with route middleware:
// middleware/auth.ts
export default defineNuxtRouteMiddleware(async (to) => {
const user = await getCurrentUser();
if (!user) {
return navigateTo({ path: '/login', query: { redirect: to.fullPath } });
}
});
VueFire warns that global middleware can loop, so only redirect when the target isn't already the login page. If you want the server to render pages for the signed-in user, VueFire's SSR auth features need firebase-admin, a service account exposed through GOOGLE_APPLICATION_CREDENTIALS, and optionally auth.sessionCookie: true. Client-side sign-in alone doesn't need them.
Alternative: a client-only Nuxt plugin
Without VueFire, a .client suffix keeps Firebase out of the server bundle, and public runtime config lets you change authDomain per environment:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
firebaseApiKey: '',
firebaseAuthDomain: '', // NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN overrides this
firebaseProjectId: '',
firebaseAppId: '',
},
},
});
// plugins/firebase.client.ts
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig().public;
const app = initializeApp({
apiKey: config.firebaseApiKey,
authDomain: config.firebaseAuthDomain,
projectId: config.firebaseProjectId,
appId: config.firebaseAppId,
});
return { provide: { auth: getAuth(app) } };
});
In components, const { $auth } = useNuxtApp() gives you the Auth instance, but only in the browser, so call it from event handlers or onMounted.
Authorize your hosts
In the Firebase console, enable Google under Security > Authentication > Sign-in method, then open Settings > Authorized domains and click Add domain (as of Oct 2026; older guides use Build > Authentication). Add localhost for development (Firebase recommends removing it from production projects), your production domain such as app.example.com, and your host's default domain if people sign in there.
Show your own domain on Google's sign-in screen
Firebase's docs say users may see Continue to: https://YOUR-PROJECT.firebaseapp.com during Google sign-in, because the SDK opens https://<authDomain>/__/auth/handler. Firebase's redirect best-practices page (option 3) says to forward /__/auth/ on your domain to YOUR-PROJECT.firebaseapp.com transparently (not via a 302), then change authDomain.
Nuxt deployed with a server (Node, serverless or edge preset). Nitro's proxy route rule proxies matching requests to another URL, and its docs show the /** form carrying the rest of the path across:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
'/__/auth/**': { proxy: 'https://YOUR-PROJECT.firebaseapp.com/__/auth/**' },
},
});
Test this on a preview deployment before relying on it. Nitro's docs don't spell out how the proxy rule handles POST requests, which Firebase says must be forwarded too, and Nuxt's config reference marks routeRules as experimental, so re-check it after upgrades.
Static output (nuxi generate) or a plain Vue SPA. Prerendered files are served without your Nitro server, so put the forwarding on the host instead. The Netlify _redirects and vercel.json rules in the Vite guide linked below work the same way for a Vue build.
Then finish on Google's side:
- Google Cloud console > APIs & Services > Credentials > your web client under OAuth 2.0 Client IDs (as of Oct 2026 also under Google Auth Platform > Clients): add
https://app.example.com/__/auth/handlerto Authorized redirect URIs. Google says changes can take 5 minutes to a few hours. - Confirm
app.example.comis an authorized domain in Firebase. - Set
authDomaintoapp.example.com: invuefire.configfor the module setup, or withNUXT_PUBLIC_FIREBASE_AUTH_DOMAIN=app.example.comfor the plugin setup. KeepYOUR-PROJECT.firebaseapp.comfor local development unless you also proxy there.
How to confirm it worked
- Request
https://app.example.com/__/auth/handler. You should get Firebase's response, not Nuxt's error page. An error page means the route rule isn't active on this deployment (a common cause is a static deploy). - In DevTools > Network, start sign-in and check that the popup opens on
https://app.example.com/__/auth/handler?.... - Google's account chooser should name
app.example.comas the site you're continuing to. - After sign-in,
useCurrentUser()should change fromundefinedto your user, and protected routes should load without bouncing to/login.
Related problems
- Domains list and what belongs in it: Firebase authorized domains explained
- Host rewrite examples for static Vue builds: Vite + React Firebase Google sign-in
- Choosing between popup and redirect: signInWithPopup or signInWithRedirect?
- Google shows
redirect_uri_mismatch: Fix redirect_uri_mismatch and after changing authDomain - Any other
auth/...code: Firebase Auth error reference - Why Google names
firebaseapp.com: Google sign-in says "continue to xxxx.firebaseapp.com"
FAQ
Is VueFire required for Firebase Auth in Vue 3?
No. VueFire adds composables like useCurrentUser() and getCurrentUser() for router guards, but the Firebase modular SDK works directly with your own ref and onAuthStateChanged().
Why is useFirebaseAuth() null in Nuxt?
VueFire returns null from useFirebaseAuth() on the server. Call sign-in and sign-out from browser events, and use a non-null assertion in TypeScript only where the code can't run during SSR.
Do I need a service account for Nuxt Firebase auth?
Only for VueFire's SSR auth features, such as rendering pages with the signed-in user or session cookies. Plain client-side Google sign-in doesn't need firebase-admin or a service account.
Will the routeRules proxy work with nuxi generate?
Don't count on it. A static deploy usually has no Nitro server at request time to run the rule, so use your host's rewrite feature for /__/auth/* instead, then request /__/auth/handler on the live site to confirm Firebase answers.
Sources
- Authenticate Using Google with JavaScript | Firebase Authentication
- Best practices for using signInWithRedirect on browsers that block third-party storage access | Firebase
- Authentication FAQ and troubleshooting | Firebase Authentication
- Learn about and manage API keys for Firebase
- firebase-js-sdk: packages/auth/src/core/util/handler.ts
- Getting Started | VueFire
- Firebase Authentication | VueFire
- Nuxt.js | VueFire
- Authentication | VueFire (Nuxt)
- plugins | Nuxt
- Runtime Config | Nuxt
- Nuxt Configuration | Nuxt
- nuxt dev | Nuxt
- Deployment | Nuxt
- Routing | Nitro
- Server Options | Vite
- Manage OAuth Clients | Google Cloud
How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked 26 Oct 2026. Spotted something out of date? Tell us.