why this code fail to sign up on firebase? - firebase

For some reason this code fail to sign up on firebase,
app.post('/signup', (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle
}
let token, userId;
db.doc(`/users/${newUser.handle}`).get().then(doc => {
if (doc.exists) {
return res.status(400).json({ handle: 'this handle already exists' })
} else {
return firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
}
})
.then(data => {
userId = data.user.uid;
return data.user.getIdToken();
})
.then(idToken => {
token = idToken;
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
createdAt: new date().toISOString(),
userId
}
return db.doc(`/users/${newUser.handle}`).set(userCredentials)
})
.then(() => {
return res.status(201).json({ token });
})
.catch(err => {
if (err.code === "auth/email-already-in-use") {
return res.status(400).json({ email: 'Email is alrready in use' })
} else {
return res.status(500).json({ general: 'something went wrong, please try again' })
}
})
});
I always get { general: 'something went wrong, please try again' } , i am using postman to mimic the request to firebase,
This code works perfectly:
firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password)
.then(data => {
return data.user.getIdToken();
})
.then(token => {
return res.status(201).json({token})
})
.catch(err => {
console.error(err);
return res.status(500).json({error: 'something went wrongly'})
})
The first trial is from a tutorial i am following in Youtube and sadly it doesn't work

On the backend, you can use Firebase Admin SDK to get details about any user but it does not have any ability to login on behalf of user.

Related

Firebase Dispatch Error Object { "error": "Invalid claim 'kid' in auth header: 'tB0M2A' with iat: '1659290899'", }

I am trying to develop a react-native-app but everything was good. Once I have changed the authentication rules in firebase real time database. From that time, I am not able to POST/GET any request from firebase. I am storing the idToken which is returned after a user sign in the application in redux store.
case actionTypes.AUTHENTICATE_USER:
return {
...state,
isAuth: true,
token: action.payload
}
export const authUser = token => {
return {
type: actionTypes.AUTHENTICATE_USER,
payload: token
}}
The Login action code is as follows:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, returnSecuretoken: true
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})}
And I get the error while running the following code:
export const addPlace = place => (dispatch, getState) => {
let token = getState().token;
console.log("Add place Token:", token);
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`, {
method: "POST", body: JSON.stringify(place)
})
.catch(error => console.log(error))
.then(response => response.json())
.then(data => console.log("Dispatch Error", data))}
export const loadPlaces = () => (dispatch, getState) => {
let token = getState().token;
fetch(`https://first-react-native-proje-7df03-default-rtdb.asia-southeast1.firebasedatabase.app/places.json?auth=${token}`)
.catch(err => {
alert("Something Went Wrong, Sorry!");
console.log(err);
})
.then(res => res.json())
.then(data => {
const places = [];
for (let key in data) {
places.push({
...data[key],
key: key
})
}
dispatch(setPlaces(places));
})}
My firebase rule is as follows as I am still in initial phase:
{"rules": {
".read": "auth!=null" , // 2022-8-4
".write": "auth!=null", // 2022-8-4
}}
I am not getting any way to solve this. Please help.
Solved. The problem was with the returnSecureToken:true. I wrote returnSecuretoken which was creating the error. It will be:
export const tryLogin = (email, password, navigate) => dispatch => {
fetch("https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + API_KEY, {
method: "POST",
body: JSON.stringify({
email: email, password: password, ***returnSecureToken: true***
}),
headers: {
"Content-Type": "application/json"
}
})
.catch(err => {
console.log(err);
alert("Authentication Failed");
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert(data.error.message);
}
else {
dispatch(authUser(data.idToken));
navigate("Home");
}
console.log(data);
})
}

Firebase auth().onAuthStateChanged not wait until auth().signInWithCredential finish

I have login code in react native using firebase and google signin auth.
So when new user sign in using google account, I set new data. And if user has signed in before, user go to main page.
My problem is when new user sign in > code start to get signInWithCredential > set new data user, before set data finish, onAuthStateChanged was detect there is change in auth and start to get user document / data. But because it's not finish yet, it throw error 'Can Not Get UID / Undefined UID'.
This is my login page code:
const _signIn = async () => {
setInitializing(true);
try {
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
const credential = auth.GoogleAuthProvider.credential(
userInfo.idToken,
userInfo.accessToken,
);
await auth()
.signInWithCredential(credential)
.then(response => {
const uid = response.user.uid;
const data = {
uid: uid,
email: userInfo.user.email,
fullname: userInfo.user.name,
bio: 'Halo!! ..',
username: uid.substring(0, 8),
};
const usersRef = firestore().collection('users');
usersRef
.doc(uid)
.get()
.then(firestoreDocument => {
if (!firestoreDocument.exists) {
usersRef
.doc(data.uid)
.set(data)
.then(() => {
setInitializing(false); return;
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
return;
}
})
.catch(error => {
Alert.alert(JSON.stringify(error.message));
console.log('Error getting document:', error);
return;
});
});
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
setInitializing(false);
Alert.alert('Sign in canceled');
} else if (error.code === statusCodes.IN_PROGRESS) {
setInitializing(false);
Alert.alert('Signin in progress');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
setInitializing(false);
Alert.alert('PLAY_SERVICES_NOT_AVAILABLE');
} else {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
}
}};
And this is my index page code to check auth user:
useEffect(() => {
try {
NetInfo.fetch().then(state => {
if(state.isConnected === false){
Alert.alert('No Internet Connection Detected');
setInitializing(false);
return;
}
});
setInitializing(true);
await auth().onAuthStateChanged(user => {
if (user) {
const usersRef = firestore().collection('users');
usersRef
.doc(user.uid)
.get()
.then(document => {
const userData = document.data().uid;
setisLogin(userData);
})
.then(() => {
setInitializing(false);
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
}
});
} catch (error) {
Alert.alert(error);
} }, []);
How to wait auth().signInWithCredential finish? Thankyou.
If you need to perform more actions such read data from database or so after the user logs in, you should ideally unsubscribe from onAuthStateChanged. Essentially it won't trigger when the auth state changes (i.e. user logs in) and let you do your own custom actions. Once your processing is done, then you manually redirect the user to where the onAuthStateChange would have redirected is the user wa s logged in.
const authStateListenter = await auth().onAuthStateChanged(user => {
//...
})
// Unsubscribe auth state observer when _signIn function runs
const _signIn = async () => {
setInitializing(true);
authStateListenter()
}
Calling authStateListener will disable the auth state observer. It's similar to detaching Firestore's listeners.

Sequelize error handling & code optimization

My use case is fairly simple, i want to create a new user (username,email,password) but first check that the username/email doesn't exist already.
After checking, i use bcrypt to hash the password and create/store the user in my database
Here is the code i'm actually using, it works but i think it's a little too complicated so i'm wondering if there is anything i can do to make it a bit more readable/optimized
ipcMain.on('register', (e, newUser) => {
userRepo.findByUsername(newUser.username).then(
(user) => {
if (user)
e.sender.send('register-failed', "Username already exists!");
else {
userRepo.findByEmail(newUser.email).then(
(user) => {
if (user)
e.sender.send('register-failed', "Email already exists!");
else {
bcrypt.hash(newUser.password, saltRounds).then(
(hasedPassword) => {
newUser.password = hasedPassword;
userRepo.create(newUser).then(
(user) => {
e.sender.send('register-success', user.get({plain:true}));
},
(error) => {
e.sender.send('register-failed', "Unexpected Error");
}
)
}
)
}
}
)
}
},
(error) => { e.sender.send('register-failed', "Unexpected Error"); }
).catch(error => e.sender.send('register-failed', "Unexpected Error"));
});
userRepo module :
const db = require('../db.js');
const findByUsername = function (username) {
return db.models.User.findOne({
where: {
username: username
}
});
}
const findByEmail = function (email) {
return db.models.User.findOne({
where: {
email: email
}
});
}
const create = function (newUser) {
return db.models.User.create({
username: newUser.username,
email: newUser.email,
password: newUser.password
});
}
module.exports = { findByUsername, findByEmail, create }
Thanks for the help.
EDIT:
Here's a much more readable code (that may be optimized more, but i find it readable enough)
ipcMain.on('register', (e, newUser) => {
Promise.all([userRepo.isUsernameAvailable(newUser.username), userRepo.isEmailAvailable(newUser.email)])
.then(creation => {
bcrypt.hash(newUser.password, saltRounds).then(
(hashedPassword) => {
newUser.password = hashedPassword;
userRepo.create(newUser).then(
(user) => {
e.sender.send('register-success', user.get({ plain: true }));
}
).catch(error => e.sender.send('register-failed', "Unexpected internal error!"))
}
).catch(error => e.sender.send('register-failed', "Unexpected internal error!"));
}) // User already exists
.catch((exists) => e.sender.send('register-failed', exists))
})
Using the two functions to check availability of username and email
async function isUsernameAvailable(username){
const user = await findByUsername(username);
if(!user)
return Promise.resolve(`Username : "${username}" is available`)
return Promise.reject(`Username : "${username}" is already taken !`)
}
async function isEmailAvailable(email){
const user = await findByEmail(email);
if(!user)
return Promise.resolve(`Email : "${email}" is available`)
return Promise.reject(`Email : "${email}" is already taken !`)
}
You are first checking whether username exists and then checking whether email exists. However, both of them can be checked asynchronously using Promise.all.
If anyone of the username or email already exists then you can return an error message.
You have used a promise chain however code looks much cleaner and easy to read if you implement the same code using async-await.
Please refer the below blog for how to implement Promise.all using async-await.
https://www.taniarascia.com/promise-all-with-async-await/

Problem with dispatch() and if-else statement after adding another method

I have this action to fetch the details of a specific location url stored in Firebase.
The original code (Version 1) worked no problem, whereby I dispatch authGetToken(), the code recognises the token (string) stored in redux, then uses it to to fetch the stored data.
Version 1
return dispatch => {
dispatch(authGetToken())
.then(token => {
return fetch("https://myProject/location.json?auth=" + token);
})
.catch(() => {
alert("No valid token found!");
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw(new Error());
}
})
};
But now that I modified the url requirements to include the user UID as part of the url, it does not work. I know there must be a flaw in my logic but I can't see it.
What I was hoping to write is that once I dispatch authGetToken(), the token dispatches authGetUserUID then uses both strings (userUID and token) to fetch the data.
Version 2
return dispatch => {
dispatch(authGetToken())
.then(token => {
dispatch(authGetuserUID())
return fetch("https://myProject/location/"+ userUID + ".json?auth=" + token);
})
.catch(() => {
alert("No valid token found!");
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw(new Error());
}
})
};
Would appreciate you guys pointing out the obvious to me >< as I my noob eyes can't see it. Thanks in advance.
I think it might have something to do with userUID, it doesn't seem to be initialised anywhere. Maybe try something like this:
return dispatch => {
dispatch(authGetToken()).then(token => {
dispatch(authGetuserUID()).then(userUID=>{
return fetch("https://myProject/location/"+ userUID + ".json?auth=" + token);
})
})
.catch(() => {
alert("No valid token found!");
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw(new Error());
}
})
};

Link Multiple Auth Providers to an Account react-native

I'm new with react-native-firebase
I want to link the user after login with facebook provider and google provider
I tried all solutions on the internet but any of them worked.
this is my code
const loginUser = await firebase.auth().signInAndRetrieveDataWithEmailAndPassword('test#gmail.com','password888').then(async function(userRecord) {
console.log("Successfully sign in user:", userRecord.user._user);
let user = firebase.auth().currentUser;
console.log('current user ',user)
let linkAndRetrieveDataWithCredential=firebase.auth().currentUser.linkAndRetrieveDataWithCredential(firebase.auth.FacebookAuthProvider.PROVIDER_ID).then(async u=>{
console.log('linkAndRetrieveDataWithCredential u',u)
}).catch(async (e)=>{
console.log('linkAndRetrieveDataWithCredential error',e)
})
console.log('linkAndRetrieveDataWithCredential error',linkAndRetrieveDataWithCredential)
/**/
await firebase.auth().fetchSignInMethodsForEmail('sss#sss.sss')
.then(async providers => {
console.log('login index providers',providers)
}).catch(function(error){
console.log('login index providers error',error)
})
}).catch(async function(error){
console.log('login error',error,error.email)
if(error.code=='auth/user-not-found'){
}else if(error.code=='auth/wrong-password'){
errorMsg=`${L('password')} ${L('notValid')}`
}
if(errorMsg){
if (Platform.OS === 'android') {
ToastAndroid.show(
errorMsg,
ToastAndroid.LONG
)
} else {
Alert.alert(
'',
errorMsg,
[{ text: L('close'), style: 'cancel' }]
)
}
}
console.log("Error sign in user:", error.code);
})
linkAndRetrieveDataWithCredential needs an AuthCredential, in my app I use react-native-fbsdk to get the credential(You’ll need to follow their setup instructions).
This function will prompt the user to log into his facebook account and return an AccessToken, then you get the credential from firebase and finally linkAndRetrieveDataWithCredential.
linkToFacebook = () => {
LoginManager.logInWithReadPermissions(['public_profile', 'email'])
.then((result) => {
if (result.isCancelled) {
return Promise.reject(new Error('The user cancelled the request'))
}
// Retrieve the access token
return AccessToken.getCurrentAccessToken()
})
.then((data) => {
// Create a new Firebase credential with the token
const credential = firebase.auth.FacebookAuthProvider.credential(data.accessToken)
// Link using the credential
return firebase.auth().currentUser.linkAndRetrieveDataWithCredential(credential)
})
.catch((error) => {
const { code, message } = error
window.alert(message)
})
}

Resources