I'm a beginner in Next.js and Firebase. I was trying to make a log in system that has roles. I used Firebase Authentication and stored the account's roles on firestore. I connected the authentication account and firestore data by using the UID (from authentication) as the Firestore Document ID.
Ps. I'm not sure if this is the best way to do this but I am able to fetch data from a field by looking for the Document ID fetched using the UID.
What I need to happen is to get the role of the Account from the Firestore and use that for a function to push the correct page for that account type. The problem is, my pushToPage() fires first before my getData() gets the information it asks for from the firestore.
This is the LogIn function. I used auth.onAuthStateChanged to get the UID of the user.
var firebaseDocument = ' ';
var accountType = '';
var databaseRef = '';
function LogIn() {
signInWithEmailAndPassword(auth, email, password)
.then((response) => {
sessionStorage.setItem('Token', response.user.accessToken);
auth.onAuthStateChanged((user) => {
if (user) {
firebaseDocument = user.uid;
databaseRef = doc(database, 'users', firebaseDocument);
} else {
console.log('user logged out');
}
});
})
.catch((err) => {
console.log(err.code);
});
accountType = getData();
pushToPage(accountType);
}
This is the getData function where it fetches the account role
const getData = async () => {
try {
const docSnap = await getDoc(databaseRef);
if (docSnap.exists()) {
return docSnap.data().account_type;
} else {
console.log('Document does not exist');
}
} catch (e) {
console.log(e);
}
};
this is the pushToPage function that reads the var accountType value to decide on what page to go.
const pushToPage = (accountType) => {
if (accountType == 'management') {
router.push('/accounts/management');
} else if (accountType == 'dean') {
router.push('/accounts/deans');
} else {
router.push('/accounts/faculty');
}
};
Running this code does not only make my Program wait for the firebase response but also displays this error
Unhandled Runtime Error
FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore
I didn't use collection() though.
Also, I searched for similar problems and I think I need to place a .then() function somewhere or somekind of Asynchronous Programming technique. Unfortunately, I struggle in understanding these.
I hope I can find help here. Thanks guys.
I don't think I need the .then() function anymore. I just called the pushToPage() inside the getData.
const getData = async () => {
try {
const docSnap = await getDoc(databaseRef);
if (docSnap.exists()) {
accountType = docSnap.data().account_type;
pushToPage(accountType);
} else {
console.log('Document does not exist');
}
} catch (e) {
console.log(e);
}
};
I'm developing a dApp using web3 library. In some case the user has to decide how they want to connect, either MetaMask or WalletConnect.
So, when the user decides to connect with WalletConnect there is no problem with the connection itself but I have an issue when I want to interact with Smart Contract. Suppose I want to approve to user amount for stake or check the balance.
export const schooseProvider = provider => {
// debugger
console.log("schooseProvider: ", provider );
if(provider === "MetaMask"){
console.log("Selected Provider: ", window.ethereum)
W3 = new Web3(window.ethereum)
}
else if(provider === "WalletConnect"){
const provider = new WalletConnectProvider({
infuraId: '20c6beb49cd1402db84120a858bc74af',
bridge: 'https://bridge.walletconnect.org',
supportedChainIds,
rpc: {
3: 'https://ropsten.infura.io/v3/20c6beb49cd1402db84120a858bc74af'
}
})
console.log("Selected Provider: ", provider)
W3 = new Web3(provider)
}
}
export const approve = async (account) => {
try{
store.dispatch(updateAproveButtonsLoader(true))
await contract.methods.approve(stakeAddress,'10000000000000000000000000000000000000000000000000').send({from: account})
.once('receipt', function(receipt){
store.dispatch(updateApproveButtonsLoader(false))
store.dispatch(updateApproved(true))
checkAllowence(account)
})
.on('error', () => {
store.dispatch(updateApproveButtonsLoader(false))
})
}
catch(error){
store.dispatch(updateApproveButtonsLoader(false))
console.log(error)
}
}
Trust Wallet doesn't support testnets for now, however you can add it as custom chain
Im having a simple UI where i need a metamask connect button
but when i use this code i keep getting the
"Non-Ethereum browser detected. You should consider trying MetaMask!" error even though i have metamsk up an running in my browser
This is the code here:
window.addEventListener('load', async () => {
// Modern dapp browsers...
if (window.ethereum) {
window.web3 = new Web3(ethereum);
try {
await ethereum.enable();
var accounts= await web3.eth.getAccounts();
var option={from: accounts[0] };
} catch (error) {
// User denied account access...
}
}
// Legacy dapp browsers...
else if (window.web3) {
window.web3 = new Web3(web3.currentProvider);
// Acccounts always exposed
web3.eth.sendTransaction({/* ... */});
}
// Non-dapp browsers...
else {
console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
}
const ethereumButton = document.querySelector('.enableEthereumButton');
const showAccount = document.querySelector('.showAccount');
ethereumButton.addEventListener('click', () => {
getAccount();
});
async function getAccount() {
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
const account = accounts[0];
showAccount.innerHTML = account;
};
and this are the 2 buttons for account and to connect
<button class="enableEthereumButton">Enable Ethereum</button>
<h2>Account: <span class="showAccount"></span></h2>
What do I need to do to make this work, i followed the metamask tutorial but they are written so bad, they are almost useless
You dont need to use window for metamask access. You can try replacing your if with somthing like this.
if (window.ethereum) {
const web3 = new Web3(ethereum);
try {
await ethereum.enable();
var accounts = await web3.eth.getAccounts();
console.log(accounts)
} catch (error) {
// User denied account access...
}
}
The getAccount() function isn't neccesary as you should be able to pull everything from the web3.eth.* anyway.
I have used react-native-firebase version 6.2.0
When I use react-native-firebase/messaging, I found out any sendMessage() function doesn’t work.
(I use android devices and virtual machine.)
I just follow the document here
At first, I registered remoteNotification and got FCM token from it. => init()
Then, I sent upstream remoteMessage => sendMessage()
But, I could not find out where are the messages. => could not receive any messages in device and in firebase cloud messaging console.
When I sent messages from firebase cloud messaging console, I could got the message at devices.
import messaging from '#react-native-firebase/messaging';
import firestore from '#react-native-firebase/firestore';
import store from 'project3/redux/store.js';
export async function init() {
const enabled = await messaging().hasPermission();
if (enabled) {
console.log('user has permissions');
} else {
console.log('user doesnt have permission');
const enabled2 = await messaging().requestPermission();
if (enabled2) {
console.log('requestPermission');
} else {
console.log('not requestPermission');
}
}
console.log('getToken');
await messaging().registerForRemoteNotifications();
const fcmToken = await messaging().getToken();
const uid = store.getState().email;
console.log('fmcToken : ' + fcmToken);
await firestore()
.doc(`users/${uid}`)
.update({
fcmToken: fcmToken,
});
console.log(
'isRegisteredForRemoteNotifications ' +
messaging().isRegisteredForRemoteNotifications,
);
messaging().onMessage(async remoteMessage => {
console.log('FCM Message Data:', remoteMessage.data);
});
messaging().onSendError(event => {
console.log(event.messageId);
console.log(event.error);
});
}
export async function sendMessage() {
console.log('sendMessage');
await messaging()
.sendMessage({
data: {
loggedIn: Date.now().toString(),
uid: store.getState().email,
},
})
.then(msg => {
console.log(msg);
});
}
Please help me.
I found many cases about below version 5.x.x of react-native-firebase.
But, there are very few cases about 6.x.x and guide isn't also sufficient.
You may save my weeks.
I'll appreciate assistance with how to reauthenticate a user in Firebase. I wonder if it makes any sense adding all these great features if the documentation doesn't explain how to use it:
Currently, this is what I'm trying, and it ain't working. Errors as cannot read property 'credential' of undefined
In constructor:
constructor(#Inject(FirebaseApp) firebaseApp: any) {
this.auth = firebaseApp.auth();
console.log(this.auth);
}
then the function
changePassword(passwordData) {
if(passwordData.valid) {
console.log(passwordData.value);
// let us reauthenticate first irrespective of how long
// user's been logged in!
const user = this.auth.currentUser;
const credential = this.auth.EmailAuthProvider.credential(user.email, passwordData.value.oldpassword);
console.log(credential);
this.auth.reauthenticate(credential)
.then((_) => {
console.log('User reauthenticated');
this.auth.updatePassword(passwordData.value.newpassword)
.then((_) => {
console.log('Password changed');
})
.catch((error) => {
console.log(error);
})
})
.catch((error) => {
console.log(error);
})
}
}
The reauthenticate() method is called on a firebase.User, not on firebase.auth.Auth itself.
var user = firebase.app.auth().currentUser;
var credentials = firebase.auth.EmailAuthProvider.credential('puf#firebaseui.com', 'firebase');
user.reauthenticate(credentials);
Update (July 2017):
There are some breaking change in the 4.0 version of the Firebase Web SDK. From the release notes:
BREAKING: firebase.User.prototype.reauthenticate has been removed in favor of firebase.User.prototype.reauthenticateWithCredential.
As far as I can tell the reauthenticateWithCredentialis a drop-in replacement for the old method.
Here's some code that enabled users to (a) reauthenticate in Firebase and (b) change their passwords after reauthenticating for me. I researched for about an hour while writing this, so hopefully it saves someone a minute.
Wrote in VueJS:
changePassword() {
let self = this; // i use "self" to get around scope issues
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(
this.$store.state.userId, // references the user's email address
this.oldPassword
);
user.reauthenticateWithCredential(credential)
.then(function() {
// User re-authenticated.
user.updatePassword(self.newPassword)
.then(function() {
console.log("Password update successful!");
})
.catch(function(error) {
console.log(
"An error occurred while changing the password:",
error
);
});
})
.catch(function(error) {
console.log("Some kinda bug: ", error);
// An error happened.
});
Slight changes as of May 2019, see more details here. Code is as follows:
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(user.email, password);
// Prompt the user to re-provide their sign-in credentials
return user.reauthenticateWithCredential(credential);
Call changeEmail("new email","password") in onPressed directly to update the user email with no reauthentication required error
RaisedButton(
onPressed: () {
changeEmail(_emailController.text, _passwordController.text);
}
Future<void> changeEmail(String email, String password) async {
User user = await FirebaseAuth.instance.currentUser;
print(email);
print(password);
try {
try {
var authResult = await user.reauthenticateWithCredential(
EmailAuthProvider.getCredential(
email: user.email,
password: password,
),
);
user.updateEmail(email).then((_) {
print("Succesfull changed email");
_backthrow();
}).catchError((error) {
showAlertDialog(context, error.message);
print("email can't be changed" + error.toString());
});
return null;
} catch (e) {
print("2");
}
} catch (e) {
print(e.message);
showAlertDialog(context, e.message);
}
}
Hers a full example how to reauthenticate with Firebase
var pass = "abcdefg";
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(user.email, pass);
user.reauthenticateWithCredential(credential).then(() => {
console.log("Its good!");
}).catch((error) => {
console.log(error);
});
Since 2021: If you use Firebase JS API 9.x (the tree shakable version) this is the most recent way:
https://cloud.google.com/identity-platform/docs/web/reauth
With credentials
import { getAuth, reauthenticateWithCredential } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
// todo for you: prompt the user to re-provide their sign-in credentials
const credential = promptForCredentials();
reauthenticateWithCredential(user, credential).then(() => {
// ...
}).catch((error) => {
// ...
});
With popup
import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";
const auth = getAuth();
// todo for you: change to appropriate provider
const provider = new OAuthProvider('apple.com');
reauthenticateWithPopup(auth.currentUser, provider)
.then((result) => {
// ...
})
.catch((error) => {
// ...
});
This is how I re-authenticate a user in Firebase:
import { getAuth, EmailAuthProvider, reauthenticateWithCredential } from "firebase/auth";
const auth = getAuth()
const reauthenticateUser = async (email, password) => {
const user = auth.currentUser;
try {
const credential = EmailAuthProvider.credential(email, password);
await reauthenticateWithCredential(user, credential)
} catch (error) {
Alert.alert("Error", "The email or password is incorrect. Please try again.")
}
}
I was getting that re-authentication error auth/requires-recent-login when saving the primary email.
I couldn't figure out how to implement that poorly documented reauthenticateWithCredential(credential) method, so, I simply logged-out the user and redirected to login page. It's a hack but It works like charm!
firebase.auth().signOut();