Phoneauthprovider is not a function firebase react-native - firebase

Hi everybody im making a app using react-native and fire base im have this initial config at firebase config :
import firebase from 'firebase/app';
import 'firebase/auth';
import Constants from 'expo-constants';
// Firebase Config
// Initialize Firebase
export const firebaseConfig = {
apiKey: Constants?.manifest?.extra?.apiKey,
authDomain: Constants?.manifest?.extra?.authDomain,
projectId: Constants?.manifest?.extra?.projectId,
storageBucket: Constants?.manifest?.extra?.storageBucket,
messagingSenderId: Constants?.manifest?.extra?.messagingSenderId,
appId: Constants?.manifest?.extra?.appId
};
let Firebase
if (firebase.apps.length === 0) {
console.log('hello world')
Firebase = firebase.initializeApp(firebaseConfig);
}
export default Firebase;
And im triyng to call this method:
const loginUser = async() => {
switch(loginType){
case 0:
break;
case 1:
if (typeof(verificationId) == 'string') {
setLoading(true)
try {
const credential = new Firebase.auth.PhoneAuthProvider.credential(
verificationId,
verificationCode
);
await Firebase.auth.signInWithCredential(credential);
showMessage({ text: 'Phone authentication successful 👍' });
} catch (err) {
setLoading(false)
showMessage({ text: `Error: ${err.message}`, color: 'red' });
}
} else {
try {
const phoneProvider = Firebase.auth.PhoneAuthProvider();
const verificationId = await phoneProvider.verifyPhoneNumber(
phoneNumber,
recaptchaVerifier.current
);
setVerificationId(verificationId);
showMessage({
text: 'Verification code has been sent to your phone.',
});
} catch (err) {
showMessage({ text: `Error: ${err.message}`, color: 'red' });
}
}
break;
}
}
When im try to call my 'phone Login method' react-native show me this message:
im use this guide for how to configure the enviroment:
https://blog.jscrambler.com/how-to-integrate-firebase-authentication-with-an-expo-app
but using phone verification with recaptcha im not found the problem i believe the problem its in my implementation but in not found nothing
Thanks for the answers

I see you're trying to implement phone auth using firebase and I personally had success doing that using this:
async function signInWithPhoneNumber(phoneNumber) {
//1. Have the user input thei phone number into a TextInput and pass it to this function
//2. Have a confirm useState to make sure the verification code was sent successfully by firebase
//3. Check for the confirm state in the main component and show the user another TextInput to enter the verification code if confirm has a value
await firebase.auth()
.signInWithPhoneNumber(phoneNumber)
.then(confirmation => {
setConfirm(confirmation)
})
.catch(e => {
Alert.alert('Error sending verification code to this phone number')
})
}
async function confirmCode(code) {
//1. Have the code the user entered through the TextInput pass through here and call the below function
try {
let validation = await confirm?.confirm(code)
if (validation) console.log('correct code.')
} catch (error) {
Alert.alert('Invalid code.')
}
}

You're importing your own Firebase object, which is an instance of FirebaseApp. The PhoneAuthProvider class is not defined on FirebaseApp, but rather is in the (static) firebase.auth namespace.
So you either need to also import the regular Firebase Auth SDK into your code, instead of just your own Firebase object, or you can attach the firebase.authnamespace to yourFirebase` object and use it from there with:
...
if (firebase.apps.length === 0) {
console.log('hello world')
Firebase = firebase.initializeApp(firebaseConfig);
Firebase.auth = firebase.auth;
}
export default Firebase;

Related

Firebase authentication not working in NuxtJs application

In am using Firebase Authentication in my Nuxt App. I am following the Firebase Documentation for setting up Authentication using GoogleAuthProvider. In my case, onAuthStateChanged() listener returns null even after successfull redirect.
When the user enter my web application, Nuxt will execute the plugin in the client side. There the firebase configuration is initialized. Then the initUser() function defined in useFirebaseAuth.ts composable is called. If user successfully logged In, log the user details.
Note : After I encountered this error, I replaced signInWithRedirect to signInWithPopup, it works very well.
// plugins/firebase.client.ts
import { initializeApp } from "firebase/app";
import { initUser } from "~~/composables/useFirebaseAuth";
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig();
const firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
appId: "...",
messagingSenderId: "...",
};
// Initialize Firebase
const firebaseApp = initializeApp(firebaseConfig);
initUser(firebaseApp);
})
// composables/useFirebaseAuth.ts
import { FirebaseApp } from "firebase/app";
import { getAuth,signInWithPopup, GoogleAuthProvider, onAuthStateChanged, signInWithRedirect, signOut, User } from "firebase/auth";
import { equalTo, getDatabase, onValue, orderByChild, query, ref as dbRef } from "firebase/database";
export const signInUser = async () => {
const provider = new GoogleAuthProvider();
const auth = getAuth();
await signInWithRedirect(auth, provider)
}
export const initUser = async (firebaseApp: FirebaseApp) => {
const auth = getAuth(firebaseApp)
const db = getDatabase()
onAuthStateChanged(auth, user => {
if (user) {
console.log(user)
} else {
console.log("user not logged in"
return navigateTo('/login')
}
});
}
export const signOutUser = async () => {
const auth = getAuth();
await signOut(auth)
}
In the above code, I always get the user value as null. I am working on the project for 2 months. The authentication works fine almost one month ago. But it is not working now. Please help me to resolve the issue.
# node --version
v19.5.0
# npm version
{
npm: '9.3.1',
node: '19.5.0',
v8: '10.8.168.25-node.11',
uv: '1.44.2',
zlib: '1.2.13',
brotli: '1.0.9',
ares: '1.18.1',
modules: '111',
nghttp2: '1.51.0',
napi: '8',
llhttp: '8.1.0',
uvwasi: '0.0.14',
acorn: '8.8.1',
simdutf: '3.1.0',
undici: '5.14.0',
openssl: '3.0.7+quic',
cldr: '42.0',
icu: '72.1',
tz: '2022g',
unicode: '15.0',
ngtcp2: '0.8.1',
nghttp3: '0.7.0'
}
I have gone through many answers posted for same question in the stackoverflow website. But those answers didn't solved my issues.

Firebase OAuth with Google sends me to a blank page

I am trying to do a simple sign in/register with google using firebase auth for a Vue.js project I am working on. Unfortunately, both signInWithRedirect and signInWithPopup are sending me to blank pages with no error! Here is the situation:
I have configured the firebase app within the firebase console and set up google as a sign-in method. Signing in with email is working, so I know the firebase initialization is working. Here is that stuff anyway:
from main.js:
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: "****",
authDomain: "date-night-mevn.firebaseapp.com",
projectId: "date-night-mevn",
storageBucket: "date-night-mevn.appspot.com",
messagingSenderId: "1054265433143",
appId: "1:1054265433143:web:9fc18db10198531a3573b2"
};
initializeApp(firebaseConfig);
From App.vue:
import { onMounted, ref } from 'vue';
import { getAuth, onAuthStateChanged, signOut } from '#firebase/auth';
import router from './router';
const isLoggedIn = ref(false);
let auth;
onMounted (() => {
auth = getAuth();
onAuthStateChanged(auth, (user) => {
if(user) {
isLoggedIn.value = true;
} else {
isLoggedIn.value = false;
}
});
});
const handleSignOut = () => {
signOut(auth).then(() => {
router.push("sign-in");
});
};
From Sign Up page:
const signUpWithGoogle = () => {
const provider = new GoogleAuthProvider();
signInWithPopup(getAuth(), provider)
.then((result) => {
console.log(result);
router.push("/");
})
.catch((error) => {
console.log(error)
alert(error.message)
});
}
On the above section, I have tried assigning auth to a variable outside the sign in function call as well as adding an event param to the function and running
event.preventDefault() before trying to sign in, but neither did anything for me.
It doesn't matter if I use signInWithRedirect or signInWithPopup, I always get a blank page. Here is the url it is trying to load: "https://date-night-mevn.firebaseapp.com/__/auth/handler?apiKey=******&appName=%5BDEFAULT%5D&authType=signInViaRedirect&redirectUrl=http%3A%2F%2Flocalhost%3A8080%2Fregister&v=9.9.2&providerId=google.com&scopes=profile" The only thing that looks strange to me here is "appName=%5BDEFAULT%5D", but that very well may be correct. I have seen a few other posts on this topic, but many are old and none yielded a solution for me. I look forward to any help I can get, cause it sure seems like I need it!
UPDATE: Today I tried the sign in with google button from my work computer (macbook) and it worked... I am also able to sign in with google on my iPhone, just not with my windows desktop. I have tried multiple browsers and turning vpn on/off, doesn't seem to make a difference.

How can I log in a user right after his/her email has been verified using firebase/auth and react-native without creating a whole landing page?

Notice: I have seen this question, but creating a whole landing page just to verify a user seems a bit much.
I added a login functionality to my react-native app using firebase/auth with email and password. This works well so far and I have no issues doing that.
I then continued to send a verification email to a new user and only allow him/her to use the app, once the email is verified. Again, no issues here.
The next step would be to login the user right after the email was verified. This is where I'm stuck, since the onAuthStateChanged eventhandler doesn't update after the user pressed the verification link in the email.
Is there any way to listen to the emailVerified state in real-time? I tried to use polling with setInterval() but this is not great since there is a notable delay between verification and login. I read about a continueLink you can pass to sendEmailVerification, but I couldn't figure out how to make that work in react-native.
I'm using Expo and therefore the Firebase SDK, not the Firebase react native package.
Here is the code I use for the signup:
export const signUp = async (username: string, email: string, password: string) => {
try {
const auth = getAuth();
if (email && password && username) {
// sign up
const userCredential = await createUserWithEmailAndPassword(auth, email, password);
// save username in firestore
await setUserName(userCredential, username);
// send Email Verification
await sendEmailVerification(userCredential.user);
return true;
}
} catch (error) {
onError(error);
}
};
And this is my onAuthStateChanged handler:
auth.onAuthStateChanged(authenticatedUser => {
try {
if (authenticatedUser?.emailVerified) {
setUser(authenticatedUser)
} else {
setUser(null)
}
} catch (error) {
console.log(error);
}
});
So in the end I did follow this question, but I changed it a bit to fit my needs. I'll post my steps for anyone who's doing the same.
Create a simple static website with firebase init and host it on firebase or somewhere else (check the hosting tab in your firebase console to get started)
Follow this guide to create the appropriate handlers on the website
Add the following to your verificationHandler to update the user (don't forget to import firestore) (I send the userId via the continueURL, but there are probably better ways)
// You can also use realtime database if you want
firebase.firestore().collection("users").doc(userId).set({
emailVerified: true
}, {merge: true}).then(() => {
message.textContent = "Your email has been verified.";
}).catch((error) => {
message.textContent = "The verification was invalid or is expired. Please try to send another verification email from within the app.";
});
Got to authentication -> templates in your firebase console and change the action url to your hosted website's url
Add a listener to the firestore doc to your react-native app
const onUserDataChanged = (uid, callback) => {
onSnapshot(doc(firestore, "users", uid), doc => callback(doc.data()));
}
Use the data from the callback to update the login state in the app
// As an example
auth.onAuthStateChanged(authenticatedUser => {
if (authenticatedUser && !authenticatedUser.emailVerified) {
unsubscribeFirestoreListener?.();
unsubscribeFirestoreListener = onUserDataChanged(authenticatedUser.uid, (data: any) => {
if (data?.emailVerified) {
setUser(authenticatedUser);
unsubscribeFirestoreListener?.();
}
});
}
}
use the codes below for your authentication context. for user id, you should use 'user.uid'
import React, { useState, createContext } from "react";
import * as firebase from "firebase";
import { loginRequest } from "./authentication.service";
export const AuthenticationContext = createContext();
export const AuthenticationContextProvider = ({ children }) => {
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null);
const [error, setError] = useState(null);
firebase.auth().onAuthStateChanged((usr) => {
if (usr) {
setUser(usr);
setIsLoading(false);
} else {
setIsLoading(false);
}
});
const onLogin = (email, password) => {
setIsLoading(true);
firebase.auth().signInWithEmailAndPassword(email, password)
.then((u) => {
setUser(u);
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
setError(e.toString());
});
};
const onRegister = (email, password, repeatedPassword) => {
setIsLoading(true);
if (password !== repeatedPassword) {
setError("Error: Passwords do not match");
return;
}
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then((u) => {
setUser(u);
setIsLoading(false);
})
.catch((e) => {
setIsLoading(false);
setError(e.toString());
});
};
const onLogout = () => {
setUser(null);
firebase.auth().signOut();
};
return (
<AuthenticationContext.Provider
value={{
isAuthenticated: !!user,
user,
isLoading,
error,
onLogin,
onRegister,
onLogout,
}}
>
{children}
</AuthenticationContext.Provider>
);
};

login and register in nestjs with firebase

I want to create Nestjs app which do login and register like frontend, before I write this code in my Nodejs app like this:
const firebase = require('firebase');
firebase.initializeApp(config.firebase);
app.post('/login',(req,res)=>{
firebase
.auth()
.signInWithEmailAndPassword(req.body.email, req.body.password)
.then((e) => {
firebase
.auth()
.currentUser.getIdToken(true)
.then((idToken) => {
res.json({idToken});
});
})
.catch((err) => {
console.log(err);
});
});
now I want use it in Nestjs but I got some errors.
I tried this but not working:
import * as firebase from 'firebase/app';
import * as auth from 'firebase/auth';
firebase.initializeApp(clientAccount);
auth.initializeAuth(firebase.getApp());
#Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
#Post('/register')
registerUser(#Body() body) {
const { email, password } = body;
console.log({ email, password });
auth
.createUserWithEmailAndPassword(auth.getAuth(), email, password)
.then(async (user) => {
return user;
})
.catch((err: any) => {
// res.status(500).send(err);
throw new BadGatewayException(err);
});
}
createUserWithEmailAndPassword function takes three arguments but I don't know what's the first argument?
I get this error : BadGatewayException: Firebase: Error (auth/configuration-not-found).
You get this error when the authentication source you are trying to use has not been enabled in the firebase project. Go to the firebase console and enable authentication. For example:

Firestore Error - Cannot read property `firestore` of null

I am trying to use firestore with my react project after authentication to write some data to firebase. But whenever doc.set is called, I get an error saying Cannot read property firestore of null.
Here is my firebase config file.
import firebase from 'firebase/app';
const config = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
};
if (firebase.apps.length === 0) {
console.log('Initializing firebase');
firebase.initializeApp(config);
}
export default firebase;
And here is my firebase utils file which I use to access the common requirements from firebase.
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import {FIREBASE_COLLECTIONS} from './constants';
export const getIdToken = async () => {
try {
const {currentUser} = firebase.auth();
if (currentUser) {
const idToken = await currentUser.getIdToken();
return idToken;
}
return currentUser;
} catch (error) {
throw error || new Error('Error retrieving ID token');
}
};
export const logout = async () => {
try {
await firebase.auth().signOut();
} catch (error) {
throw error || new Error('Error logging out');
}
};
export const loginUser = async (email: string, password: string) => {
try {
const user = await firebase
.auth()
.signInWithEmailAndPassword(email, password);
return user;
} catch (error) {
let message = '';
switch (error.code) {
case 'auth/invalid-email':
message = 'Invalid Email Id';
break;
case 'auth/user-disabled':
message = 'User is temporarily disabled';
break;
case 'auth/user-not-found':
message = 'User not found. Please register';
break;
case 'auth/wrong-password':
message = 'Incorrect password';
break;
default:
message = 'Error logging in';
break;
}
throw new Error(message);
}
};
export const registerUser = async (email: string, password: string) => {
try {
const user = await firebase
.auth()
.createUserWithEmailAndPassword(email, password);
return user;
} catch (error) {
const errorCode = error.code;
let message = '';
switch (errorCode) {
case 'auth/email-already-in-use':
message = 'Email already in use';
break;
case 'auth/invalid-email':
message = 'Invalid email ID';
break;
case 'auth/weak-password':
message = 'Weak password';
break;
default:
message = 'Error registering user';
break;
}
throw new Error(message);
}
};
export const signInWithGoogle = async () => {
const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({prompt: 'select_account'});
const scopes = ['profile', 'email'];
scopes.forEach(scope => provider.addScope(scope));
try {
return await firebase.auth().signInWithPopup(provider);
} catch (error) {
let message = '';
switch (error.code) {
case 'auth/account-exists-with-different-credential':
message = 'Account exists with another sign in type';
break;
case 'auth/popup-closed-by-user':
message = 'Login popup closed';
break;
default:
message = 'Error signing in';
break;
}
throw new Error(message);
}
};
export const isLoggedIn = (): boolean => {
const {currentUser} = firebase.auth();
return currentUser !== null;
};
export const getUserDoc = (
id: string
): firebase.firestore.DocumentReference => {
return firebase
.firestore()
.collection(FIREBASE_COLLECTIONS.USERS)
.doc(id);
};
export default firebase;
I'm calling the getUserDoc function from the firebase utils and using it to write data to the user.
function* registerWithPassword(user: UserInput) {
try {
const userData: firebase.auth.UserCredential = yield call(
registerUser,
user.email,
user.password
);
if (userData === null || userData.user === null) {
yield put(
authFailureAction.failure({
register: 'Unable to register user',
})
);
} else {
const userDoc = getUserDoc(userData.user.uid);
yield call(
userDoc.set,
{labels: [], pinnedNotes: [], name: user.name},
{merge: true}
);
}
} catch (e) {
console.log({e});
yield put(
authFailureAction.failure({
register: e.message || 'Unable to register user',
})
);
}
}
When userDoc.set is called, the error occurs.
From some debugging, it looks like firebase is null. That's why firebase.firestore() throws an error.
But if firebase is null, auth shouldn't work too but I haven't had any problems with firebase auth.
Also note that I am importing firebaseConfig.js in my index.js file, so I'm sure that firebase has been initialized. This is also due to the fact that users are being registered but for some reason when I'm accessing firestore from firebase.firestore(), firebase is null.
You can access the project here. Try to register a user and you'll see the error. Since it depends on Firebase, you'll have to add a relevant .env file.
You have to use the firebase that has been initialized.
import firebase from 'firebase/app'; <-- This one hasn't been initialized.
...
firebase.initializeApp(firebaseConfig);
export default firebase; <-- This one is initialized.
In your firebase_config, add firestore, and auth
import firebase from 'firebase/app';
import 'firebase/auth'; <----- add this here.
import 'firebase/firestore'; <----- add this here.
const config = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
};
if (firebase.apps.length === 0) {
console.log('Initializing firebase');
firebase.initializeApp(config);
}
export default firebase;
Change the first 3 lines.
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import {FIREBASE_COLLECTIONS} from './constants';
export const getIdToken = async () => {
try {
const {currentUser} = firebase.auth();
if (currentUser) {
const idToken = await currentUser.getIdToken();
....
to
import firebase from './firebase_config.js'; // or wherever your firebase.initializeApp(...) live.
import {FIREBASE_COLLECTIONS} from './constants';
export const getIdToken = async () => {
try {
const {currentUser} = firebase.auth();
if (currentUser) {
const idToken = await currentUser.getIdToken();
....
Good day.
The error may be occurring because of the issue with the multiple firebase imports/exports done in files instead of a single module as a source.
The firebase module could be exported only in firebase_config file, and then be imported from there in other files.
So in firebase_utils, you can add instead of:
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
import firebase from './firebase-config.js';
You can also remove export default firebase; from firebase_utils to prevent firebase namespace from getting overwritten.
So the final firebase_config.js file may look as:
// Firebase App (the core Firebase SDK)
var firebase = require("firebase/app");
// Add the Firebase products that you want to use
require("firebase/auth");
require("firebase/firestore");
// Your app's Firebase project configuration
var firebaseConfig = {
// ...
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// Single source for all imports of the firebase module
export default firebase;
You can also take reference from this article and this GitHub repo for firebase importing examples.

Resources