deleting user, problems with reauthenticating firebase - javascript

Hello I'm trying to reauthenticate the user before they delete their account but I'm having one problem I can't seem to solve; how do I obtain the user's password if I didn't save it since that would be a privacy issue. I've seen other posts about this but they don't mention how they got the password. This is my code for deleting account:
const onDeleteAccountPress = () => {
firebase.database().ref('users/'+userId).remove()
var userReauth = firebase.auth().currentUser
const credential = firebase.auth.EmailAuthProvider.credential(userReauth.email,userProvidedPassword)
userReauth.reauthenticateWithCredential(credential)
for(let i =0; i < goalCounter; i++){
firebase.database().ref('goals/'+(courseGoals[i].id)).remove()
}
userReauth.delete()
.then(function(){
props.navigation.navigate('Login');
props.navigation.reset({ index: 0, routes: [ { name: 'Login' } ] });
}).catch(function(error){
console.log(error)
console.log('there is something wrong')
})
}

When the user logs in, you can store the password inside localStorage, then if the user wants to delete the account, you can get the password from the storage and pass it to the EmailAuthProvider.credential() method.

Related

Check Firestore Database boolean return value

I am working for a task related to react native app based user management. After they successful sign up themselves as a user, I include a data which is store Boolean value and I have named it as emailVerifiedAccount (this is the stored data if they registered themselves successful and indicate if they are a verified user if they click on email verification link send to them). In login screen I would like to check the Boolean value that I get from firestore in onAuthStateChanged and only direct them to index screen when the emailVerifiedAccount that I get is return true. Code below is authstatechanged for login screen .
const onAuthStateChanged = (user) => {
if (user) {
checkEmailVerifiedAccount=firestoreService.isEmailVerifiedAccount(user);
try {
if(checkEmailVerifiedAccount===true){
navigation.navigate('Index');
}else{
Alert.alert(
"Verify as a Playbookx user",
"Please click on email verification link send to your email. If you do not receive any email ,please contact user support",
"You may come back to login again after you verified your email",
[
{ text: "OK"}
]
)
}
} catch (error) {
console.log(error);
}
}
};
and in firestore.js is where all the code and function that is related with Firestore database. isEmailVerifiedAccount is one of the class object which checking verified user using email.
isEmailVerifiedAccount = async (user) => {
return await firestore()
.collection('users')
.doc(user)
.get()
.then(snapshot => {
if (snapshot.exists){
const user=snapshot.data();
const emailVerifiedAccount={
emailVerifiedAccount:user.emailVerifiedAccount
};
return emailVerifiedAccount
}
})
.catch(error => {
console.log(error);
});
};
And the problem that I facing right now is that, it lead me to index screen when the emailVerifiedAccount in Firestore is false. Picture below is the structure for Firestore.
Your isEmailVerifiedAccount function is asynchronous, so when calling it you have to await the result:
checkEmailVerifiedAccount = await firestoreService.isEmailVerifiedAccount(user);
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
checkEmailVerifiedAcccount seems to be an object but you are checking if it's equal to true. Either return user.emailVerifiedAccount directly from isEmailVerifiedAccount function or read that property like this:
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
if(checkEmailVerifiedAccount.emailVerifiedAccount) {
navigation.navigate('Index');
}

How to implement the change password API in typescript with jwt?

I created login api and implemented jwt in that. Now I am trying to implement change_password with jwt authentication with cookies or local storage. I tried and not able to do that. Can anybody help me with the change password api and also i attached my Login API.
export let login=async(req:Request,resp:Response)=>{
var {email , password} = req.body;
try{
const user=await User.findOne({email}).lean();
if(!user){
return resp.json({message:"user not found"})
}
if(await bcryptjs.compare(password,user.password)){
const token=jwt.sign(
{
id:user._id,
username:user.email
},config.token.secret)
return resp.json({status:'ok',data:token})
}
return resp.json({status:'error',data:'comming soon'})
}catch(error){
console.log(error);
}
}
You can create a different route for change password and there can be multiple ways for doing this. Let keep it simple.
You can ask user the username and existing password and a new password. Check if the existing password matches the password in DB and hash the new password and save it.
app.post('/passwordChange', (req, res) => {
const {username, password, newPassword} = req.body;
const user = User.findOne({username});
//check the password matches and then update the User with new password
const matched = await bcryptjs.compare(password,user.password);
if (matched) {
User.updateOne({}) // go your things
}
else {
// do tell your to update correct password
}
})
There can be multiple simple and complex ways to achieve it. The above code is a pseudocode, modify to use it in the code.

Firebase Sign Up with username. Cliend Side + Security Rules or Backend?

I have implemented a Firebase SignUp with username, email and password. Basically what I am doing is:
1- Create user with email and password (if the username and email are not used by other users)
2- Add the username to the user
Like this:
firebase
.createUserWithEmailAndPassword(email, password)
.then((currentUser) => {
// Get the username from the input
const username = this.usernameInput.current.getText();
// Create a user with this username and the current user uid in the db
firebase.createUserWithUsername(username, currentUser.user.uid); // <----------
})
.catch((err) => {
// ...
});
And my createUserWithUsername function basically do this:
createUserWithUsername = (username, userId) => {
/*
Create a document in the usernames collection
which uid (of the document itself, not a field) is the given username.
*/
// Pass username to lowercase
username = username.toLowerCase();
// Initial user's data
const data = {
email: this.auth.currentUser.email,
username,
};
return this.db
.collection("usernames")
.doc(username)
.set({ userId })
.then(() => {
this.db.collection("users").doc(userId).set(data);
})
.catch((err) => {
console.log(err);
throw err;
});
/*
Pd: As firestore automatically removes empty documents, we have to
assign them a field. The user's id is a good option, because it will help us to
update usernames faster, acting like a 'Foreign Key' in a NoSql DB.
*/
};
My question is? Is it wrong to leave this code on the client side? Can it be a security problem? Do I need to move this to a cloud function / backend?
This is my firestore security rule for the usernames collection:
match /usernames/{username} {
function isUsernameAvailable() {
return !exists(/databases/$(database)/documents/usernames/$(username));
}
allow read: if true;
allow write, update: if isSignedIn() && isUsernameAvailable();
// TODO - Allow delete?
}
I would really appreciate any guide for this. Thank you.

Why is Firebase's "getRedirectResults()" returning "{user: null}"?

Currently, when the user goes through the Social auth (via redirects), it successfully creates a user under Firebase Authentication, but fails to retrieve the Google/Facebook API's data. Perplexed as to how it's failing to retrieve the data when the Auth is successful.
I used to only have the SignInWithPopup (which works perfectly fine), but am trying to get getRedirectResults to work too (for mobile).
Given the behavior I've been seeing, the problem is most likely with the getRedirectResults. Most likely not the social API setup, because otherwise the user would never get created in Authentication.
The following code resides in componentDidMount (this is a React.js app):
if (this.state.device === 'mobile') {
firebase.auth().getRedirectResult().then(function(result) {
console.log('login successful! Data is:');
console.log(result);
if (result.credential) {
var provider = result.credential.providerId;
self.handleSocialAuth(provider, result);
}
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
});
}
results is supposed to contain the user's data, keeps returning:
login successful! Data is:
{user: null}
I have not deviated from official docs examples, which is why I'm confused.
firebase.auth().getRedirectResult() - is called after the page loads.
Official doc link: https://firebase.google.com/docs/auth/web/google-signin
Use the below method to retrieve the user that is logged in.
firebase.auth().onAuthStateChanged(function(user) {
console.log(user);
});
If no user is logged in the user will be null.
Live example:
checkAuthStatus(){
firebase.auth().onAuthStateChanged(user => {
this.setState({ btnWithImg: user });
if(user !== null){
this.setState({ userIsLoggedIn: true });
this.props.toggleLogIn();
}
});
}
You should call firebase.auth().getRedirectResult() only when user has been authenticated. Example
firebase.auth().onAuthStateChanged(user => {
if (user) {
const result = await firebase.auth().getRedirectResult();
assert(result.user, 'user is empty')
}
});

Firebase Document for each user?

I am wondering how to make a document for each user as they create their account (with Firebase Web). I have Firebase Authentication enabled and working, and I'd like each user then to have a document in Cloud Firestore in a collection named users. How would I get the UID and then automatically create a document for each user? (I am doing this so that calendar events can be saved into an array field in the document, but I need a document for the user to start with). I am aware and know how to make security rules for access, I just don't know how to make the document in the first place.
Thanks!
While it is definitely possible to create a user profile document through Cloud Functions, as Renaud and guillefd suggest, also consider creating the document directly from your application code. The approach is fairly similar, e.g. if you're using email+password sign-in:
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function(user) {
// get user data from the auth trigger
const userUid = user.uid; // The UID of the user.
const email = user.email; // The email of the user.
const displayName = user.displayName; // The display name of the user.
// set account doc
const account = {
useruid: userUid,
calendarEvents: []
}
firebase.firestore().collection('accounts').doc(userUid).set(account);
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Aside from running directly from the web app, this code also creates the document with the user's UID as the key, which makes subsequent lookups a bit simpler.
You´ll have to set a firebase function triggered by the onCreate() Auth trigger.
1. create the function trigger
2. get the user created data
3. set the account data.
4. add the account data to the collection.
functions/index.js
// Firebase function
exports.createAccountDocument = functions.auth.user().onCreate((user) => {
// get user data from the auth trigger
const userUid = user.uid; // The UID of the user.
//const email = user.email; // The email of the user.
//const displayName = user.displayName; // The display name of the user.
// set account doc
const account = {
useruid: userUid,
calendarEvents: []
}
// write new doc to collection
return admin.firestore().collection('accounts').add(account);
});
If you are using Firebase UI to simplify your life a lil, you can add a User document to a "/users" collection in Firestore only when that user first signs up by using authResult.additionalUserInfo.isNewUser from the signInSuccessWithAuthResult in your UI config.
I'm doing something like this in my project:
let uiConfig = {
...
callbacks: {
signInSuccessWithAuthResult: (authResult) => {
// this is a new user, add them to the firestore users collection!
if (authResult.additionalUserInfo.isNewUser) {
db.collection("users")
.doc(authResult.user.uid)
.set({
displayName: authResult.user.displayName,
photoURL: authResult.user.photoURL,
createdAt: firebase.firestore.FieldValue.serverTimestamp(),
})
.then(() => {
console.log("User document successfully written!");
})
.catch((error) => {
console.error("Error writing user document: ", error);
});
}
return false;
},
},
...
}
...
ui.start("#firebaseui-auth-container", uiConfig);
The signInSuccessWithAuthResult gives you an authResult and a redirectUrl.
from the Firebase UI Web Github README:
// ...
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
// If a user signed in with email link, ?showPromo=1234 can be obtained from
// window.location.href.
// ...
return false;
}

Categories