firebase.auth.GoogleAuthProvider is not a constructor - firebase

I'm trying to use google sign using firebase in the Vue framework. I don't know what the error is this can anyone help me with this.
vue.runtime.esm.js?2b0e:1888 TypeError: _firebase_js__WEBPACK_IMPORTED_MODULE_2__.fb.auth.GoogleAuthProvider is not a constructor
at VueComponent.socialLogin (Signin.vue?3d55:76)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at HTMLButtonElement.invoker (vue.runtime.esm.js?2b0e:2179)
at HTMLButtonElement.original._wrapper (vue.runtime.esm.js?2b0e:6917)
this is my code
firebase.js
import firebase from "firebase";
var firebaseConfig = {
config
};
const fb=firebase.initializeApp(firebaseConfig);
export { fb };
Sign in.vue
<script>
import { fb } from "../firebase.js";
export default {
name: "Signin",
components: {},
data() {
return {
};
},
methods: {
socialLogin() {
const provider = new fb.auth.GoogleAuthProvider();
fb.auth().signInWithPopup(provider).then((result) => {
this.$router.replace('home');
}).catch((err) => {
alert('Oops. ' + err.message)
});
}
}
};
</script>

The auth property (not the auth() function) is available on the static firebase object, not your firebase app.
You want something more like this
import firebase from "firebase/app"
import "firebase/auth" // 👈 this could also be in your `firebase.js` file
const provider = new firebase.auth.GoogleAuthProvider()

Related

provider.credential' is undefined in Expo Firebase Google authentication

I'm very new and trying to set Firebase Google authentication in Expo RN app,
Expo docs code snippet below:
https://docs.expo.dev/guides/authentication/#google
import * as React from 'react';
import * as WebBrowser from 'expo-web-browser';
import { ResponseType } from 'expo-auth-session';
import * as Google from 'expo-auth-session/providers/google';
import { initializeApp } from 'firebase/app';
import { getAuth, GoogleAuthProvider, signInWithCredential } from 'firebase/auth';
import { Button } from 'react-native';
// Initialize Firebase
initializeApp({
/* Config */
});
WebBrowser.maybeCompleteAuthSession();
export default function App() {
const [request, response, promptAsync] = Google.useIdTokenAuthRequest(
{
clientId: 'Your-Web-Client-ID.apps.googleusercontent.com',
},
);
React.useEffect(() => {
if (response?.type === 'success') {
const { id_token } = response.params;
const auth = getAuth();
const provider = new GoogleAuthProvider();
const credential = provider.credential(id_token);
signInWithCredential(auth, credential);
}
}, [response]);
return (
<Button
disabled={!request}
title="Login"
onPress={() => {
promptAsync();
}}
/>
);
}
I'm getting error something like that:
TypeError: provider.credential is not a function. (In 'provider.credential(_id_token)', 'provider.credential' is undefined)
Any solution?
Thanks in advance
Replace the following code:
const provider = new GoogleAuthProvider();
const credential = provider.credential(id_token);
with:
const credential = GoogleAuthProvider.credential(idToken);
I believe the expo docs need to be updated to reflect this.

Vue + Pinia + Firebase Authentication: Fetch currentUser before Route Guard

Recently I started to use Pinia as a global store for my Vue 3 Project. I use Firebase for the user authentication and am trying to load the current user before Vue is initialized. Ideally everything auth related should be in a single file with a Pinia Store. Unfortunately (unlike Vuex) the Pinia instance needs to be passed to the Vue instance before I can use any action and I believe that is the problem. On first load the user object in the store is empty for a short moment.
This is the store action that is binding the user (using the new Firebase Web v9 Beta) in auth.js
import { defineStore } from "pinia";
import { firebaseApp } from "#/services/firebase";
import {
getAuth,
onAuthStateChanged,
getIdTokenResult,
} from "firebase/auth";
const auth = getAuth(firebaseApp);
export const useAuth = defineStore({
id: "auth",
state() {
return {
user: {},
token: {},
};
},
actions: {
bindUser() {
return new Promise((resolve, reject) => {
onAuthStateChanged(
auth,
async (user) => {
this.user = user;
if (user) this.token = await getIdTokenResult(user);
resolve();
},
reject()
);
});
},
// ...
}})
and this is my main.js file
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createPinia } from "pinia";
import { useAuth } from "#/store/auth";
(async () => {
const app = createApp(App).use(router).use(createPinia());
const auth = useAuth();
auth.bindUser();
app.mount("#app");
})();
How can I set the user before anything else happens?
I figured it out. Had to register the router after the async stuff
//main.js
(async () => {
const app = createApp(App);
app.use(createPinia());
const { bindUser } = useAuth();
await bindUser();
app.use(router);
app.mount("#app");
})();

Correct way of reusing functions in Composition API

I use Vue3 Composition API and am trying to explore its reusability possibilities. But I feel that I don't understand how it should be used.
For example, I extracted the login function to a file, to use it on login, and also after registration.
#/services/authorization:
import { useRoute, useRouter } from "vue-router";
import { useStore } from "#/store";
import { notify } from "#/services/notify";
const router = useRouter(); // undefined
const route = useRoute(); // undefined
const store = useStore(); // good, but there is no provide/inject here.
export async function login(credentials: Credentials) {
store
.dispatch("login", credentials)
.then(_result => {
const redirectUrl =
(route.query.redirect as string | undefined) || "users";
router.push(redirectUrl);
})
.catch(error => {
console.error(error);
notify.error(error.response.data.message);
});
}
interface Credentials {
email: string;
password: string;
}
#/views/Login:
import { defineComponent, reactive } from "vue";
import { useI18n } from "#/i18n";
import { login } from "#/services/authorization";
export default defineComponent({
setup() {
const i18n = useI18n();
const credentials = reactive({
email: null,
password: null
});
return { credentials, login, i18n };
}
});
And the problem is that route and router are both undefined, because they use provide/inject, which can be called only during setup() method. I understand why this is happening, but I don't get what is correct way to do this.
Currently, I use this workaround #/services/authorization:
let router;
let route;
export function init() {
if (!router) router = useRouter();
if (!route) route = useRoute();
}
And in Login (and also Register) component's setup() i call init(). But I feel that it's not how it's supposed to work.

firebase and gatsby build don't work well together

I get the following error when I try to login:
u.a.auth is not a function
The error is on this line in Login.js:
app.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);
At the top, I have import app from "./base.js";
In base.js, I have
import firebase from 'firebase/app';
var config = {
....
};
var app;
if(firebase.apps && firebase.apps.length > 0) {
app = firebase.apps[0];
} else {
app = firebase.initializeApp(config);
}
export default app;
That's after I run
gatsby build
gatsby serve
Hello here's how I did it. It worked fine:
import React from "react";
import firebase from "firebase";
...
const LoginForm = () => {
const login = values => {
firebase
.auth()
.signInWithEmailAndPassword(values.email, values.password)
.then(() => { firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION);
navigate("/app/profile");
})
.catch(error => {
console.log("do something with the error:", error);
});
}
return(
<form onSubmit={login}>
form details
</form>
);
};
export default LoginForm;

this.$firebase is undefined

I'm building my first Vue.js app, trying to use vuex with vuexfire.
//main.js
import firebase from 'firebase';
...
Vue.prototype.$firebase = firebase.initializeApp(config);
...
firebase.auth().onAuthStateChanged(() => {
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
router,
render: h => h(App),
created() {
this.$store.dispatch('setDealsRef');
},
});
});
router.beforeEach((to, from, next) => {
const currentUser = firebase.auth().currentUser;
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
if (requiresAuth && !currentUser) {
next('/signin');
} else if (requiresAuth && currentUser) {
next();
} else {
next();
}
});
And:
//store/index.js
import Vue from 'vue';
import Vue from 'vue';
import Vuex from 'vuex';
import { firebaseMutations } from 'vuexfire';
...
Vue.use(Vuex);
const db = this.$firebase.firestore();
const dealsRef = db.collection('deals');
And:
//store/mutations.js
export default {
SET_USER(state) {
state.user = this.$firebase.auth().currentUser;
},
...
}
This complies OK, but throws TypeError: this.$firebase is undefined[Learn More] in the console.
Any idea what I'm doing wrong? I think I've read every relevant tutorial and StackOverflow questions, and tried everything.
When you do:
Vue.prototype.$firebase = firebase.initializeApp(config);
You add $firebase to the Vue instance. So for
this.$firebase
to work, the this should be a Vue insteance. In other words, that line must execute inside a Vue method/hook/computed/etc.
And the code you show, doesn't do that:
const db = this.$firebase.firestore();
in the code above, the this is the outer context. (Probably is window.)
So for it to work outside a Vue instance, you have to do:
const db = Vue.prototype.$firebase.firestore();
Provided the line above executes after (in time/order) the line where you initialize the $firebase.
I think I solved the problem:
Moving firebase initialization to store.js
Changing firebase.auth().onAuthStateChanged(() => { to Vue.prototype.firebase.auth().onAuthStateChanged(() => { in main.js
Importing firebase as: import firebase from '#firebase/app';
import '#firebase/firestore';

Resources