Change Password using react native and Firebase - javascript

In our project there is an option that the user can change their password. To do that
Before change the password user must enter current password, then check whether the entered password is matched with the saved password right now.
If it is OK, Then User has to update the old password (saved password) with new password.
I am using react native and Firebase for the developing of the project. If any one knows the solution, please let me know...

Firebase Auth won't let you change a password unless you are recently authenticated. If you try to updatePassword without being recently authenticated, you will get an error auth/requires-recent-login.
Here is how you can do it:
// Ask signed in user for current password.
const currentPass = window.prompt('Please enter current password');
const emailCred = firebase.auth.EmailAuthProvider.credential(
firebase.auth().currentUser, currentPass);
firebase.auth().currentUser.reauthenticateWithCredential(emailCred)
.then(() => {
// User successfully reauthenticated.
const newPass = window.prompt('Please enter new password');
return firebase.auth().currentUser.updatePassword(newPass);
})
.catch(error = > {
// Handle error.
});
Note the above example, uses window.prompt for illustration. You would use your own equivalent react-native UI here instead.

Related

How to use an action code and then get the current user with firebase?

I am designing 2 pages for a user signing up. The first page is where the user enters their email only. I then perform this code.
await createUserWithEmailAndPassword(auth, email.value, bcrypt.hashSync(email.value, 6))
.then(async (userCredential) => {
sendEmailVerification(userCredential.user)
loading = false
navigate('/verifyEmail')
})
.catch((error) => {
log.error(`Error registering user: ${error}`)
errorMessage = error.message
isEmailInvalid = true
loading = false
})
This sends the user a verification email, which they then click on to set their password and name:
let oobCode = ''
oobCode = window.location.href.split('oobCode=')[1].split('&')[0]
const email = window.location.href.split('email=')[1].split('/')[0]
let user = auth.currentUser
await applyActionCode(auth, oobCode)
.then(async (result) => {
console.log(auth.currentUser)
Promise.all([
updateProfile(auth.currentUser, {displayName: firstName + ' ' + lastName}),
updatePassword(auth.currentUser, password),
])
console.log('Welcome', firstName, lastName)
await setUser('local', undefined, auth.currentUser)
})
However at this point, auth.currentUser will be null if the user has clicked on this link on a different browser. A quick workaround would be to create a user with password 'password' and then sign them in after applying the action code. However this has a big security flaw obviously, my current idea just encrypts their email as a temporary password in hopes they cannot guess it and sign in.
I guess my question is, how do I update the user upon applying an action code? If I can't do this what flow of operations should I change?
My question is, how do I update the user upon applying an action code?
If the user is using another browser it is not possible since he/she does not know the password.
If I can't do this what flow of operations should I change?
IMHO you are overcomplexifying the onboarding process. The common approach is to create the account with the password being chosen by the user (which, in your case, should happen in the first screen) and send the email for verification.
In parallel you deny access to the Firebase back-ends (DBs, Cloud Storage, etc.) to users with non verified email via the Security Rules.
Upon email verification you sign in the user:
If it is from the same browser the users is actually already signed in (side effect of the use of createUserWithEmailAndPassword()
If it is in a different browser the user just has to enter his email and password (which he/she knows)

AWS Cognito Migrate User Lambda Force Reset Password

I have an issue I've been unable to resolve. I'm using AWS Cognito User Pools with a user migration lambda function to import users on the fly. After successfully validating a user's password, I'd like to check if this password meets the requirements Cognito enforces. As per the docs, this should be done in code:
Amazon Cognito doesn't enforce the password strength policy that you configured for the user pool during migration using Lambda trigger. If the password doesn't meet the password policy that you configured, Amazon Cognito still accepts the password so that it can continue to migrate the user. To enforce password strength policy and reject passwords that don't meet the policy, validate the password strength in your code. Then, if the password doesn't meet the policy, set finalUserStatus to RESET_REQUIRED.
However, when I set finalUserStatus to RESET_REQUIRED, I see behavior I don't understand. When logging in for the first time, I see the following, which seems correct:
At this time, I also receive an email with Subject: "Your temporary password" and body: "Your username is ...#gmail.com and temporary password is l6*NWOEp.". I thought this was odd because I hadn't submitted the above form yet. When I enter my email in the above form, I receive:
I don't receive any additional emails. When I fill out this form, I receive the same error.
When I go back to the sign in page and use the temporary password I received in the email, I am forwarded to the first form above: the one with the "Password reset required for user due to security reasons".
Below is the code, I've removed unrelated config and error handling:
export const lambdaHandler = async (event: any, context: any): Promise<any> => {
if (event.triggerSource == "UserMigration_Authentication") {
const userName = event.userName;
const password = event.request.password;
const user = await authenticateUser(userName, password);
event.response.userAttributes = {
"email": user.email,
"username": user.email,
"email_verified": "true",
};
if (passwordIsWeak(password) { // always true for testing purposes
event.response.finalUserStatus = "RESET_REQUIRED";
}
context.succeed(event);
}
};
The user in my Cognito User Pool has a Confirmation Status of "Reset required".
I've tried many combinations of finalUserStatus (RESET_REQUIRED, CONFIRMED, FORCE_CHANGE_PASSWORD) and messageAction (SUPPRESS, RESEND) returned in event.response. Anyway, thanks for any help provided!

i am creating login api and hashed password using bcrypt

I want to create a register login logout system. at time of registration i am taking email and password
and storing hashed password. now when logging in i want to compare password entered to hashed password. so basically I want to know how can I compare and check plain password with hashed passwords
I think this is a duplicate question but am not able to mark it as such.
This should work, taken from the bcryptJS docs.
Sync
// Load hash from your password DB.
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
// result == true
});
Promise
// Load hash from your password DB.
bcrypt.compare(myPlaintextPassword, hash).then(function(result) {
// result == true
});

Firebase Database - Login

I have a register page working well, this is my database.
enter image description here
Each one has an ID and you Login using Username and password,
And I am using this code, to verify if the username is in database.
ref.child("accounts").orderByChild("lowerun").equalTo(username.toLowerCase()).once("value",snapshot => {
if (snapshot.exists()){
const userData = snapshot.val();
console.log(userData)
}
})
But how do I get the password for the username?
Dudis! Welcome to SO! It looks like you're using Firebase Realtime Database? I think you're using the database API incorrectly if you're trying to fetch user number 1 in your accounts. Here is something you could try:
database
.ref("main/accounts")
.child(userId)
.once("value", snapshot => {
// check if snapshot exists
// log your snapshot.val()
})
Also, as Doug suggested, I would strongly suggest using Firebase Authentication.

Firebase redirect user to a page after clicking verification link

I'm using firebase in my web app with Ionic and I would like to redirect the user to a specific page (the login page, in my case) after he clicks on the link in the verification email.
At the moment, when the user clicks on the verification link, he is redirected on another browser page that says that he has confirmed the email.
I would like to redirect him directly to a page of my web app, without passing through that confirmation.
Is it possible to do that?
Yes it's possible. Look in the firebase.console on the left for "Authentication".
Then find "Templates" and look for "Email address verification". I think it's default opened. On the template you will see a small pencil, click on it. After that you can change your template however you want. At the bottom you will find the link "customize action URL". Open this link, paste your URL in the modal window and save. That's it.
I couldn't get any of the solutions here to work. So after looking up the docs I found that you add a continue URL after the email verification to which the firebase will redirect to after confirming. https://firebase.google.com/docs/auth/web/passing-state-in-email-actions
After email is verified you might also have to force refresh the firebase token if you use email_verified in your firebase rules.
You can do what I did.
Pass ActionCodeSettings to sendEmailVerification.
auth.createUserWithEmailAndPassword(email, password)
.then((res) => {
res.user.sendEmailVerification({
url: "https://example.com/path?confirm_email=true",
});
return createUser({ email, uid: res.user.uid, name });
})
This will make firebase redirect to https://example.com/path?confirm_email=true after email verification. The confirm_email is so that I know when to force refresh the firebase token.
(Optional)
Once redirected to the page you want you can check for the confirm_email param and force refresh the token accordingly.
const urlParams = new URLSearchParams(window.location.search);
const isConfirmingEmail = urlParams.get('confirm_email');
auth.currentUser.getIdToken(!!isConfirmingEmail).then(() => {
// Refreshed Token
})
Here is my code that helped me. I am only providing you necessary code that you need You have to fill rest of the code by yourself 😁.
Firebase v9 example
import React from "react";
import {
createUserWithEmailAndPassword,
sendEmailVerification
} from "#firebase/auth";
import {useHistory} from "react-router-dom"
export default function SignUp() {
const history = useHistory()
async function submit(e) {
e.preventDefault() // Prevent default.
// Sign your user using createUserWithEmailAndPassword
// Provide user's email and password
await createUserWithEmailAndPassword(email, password);
// Send verification email.
await sendEmailVerification(userCredentials.user);
let interval = setInterval(async() => {
if (userCredentials.user.emailVerified) {
clearInterval(interval);
history.push("/desired-link");
}
await userCredentials.user.reload();
}, 2000);
}
return < > { /* your sign up form */ } < />;
}
Firebase v8 code:
import React from "react";
import firebase from "firebase"
import {useHistory} from "react-router-dom"
export default function SignUp() {
const history = useHistory()
async function submit(e) {
e.preventDefault() // Prevent default.
// Sign your user using createUserWithEmailAndPassword
// Provide user's email and password
let userCredentials = await firebase.auth.createUserWithEmailAndPassword(email, password);
// Send verification email.
await userCredentials.user.sendEmailVerification()
let interval = setInterval(async () => {
if (userCredentials.user.emailVerified) {
clearInterval(interval);
history.push("/desired-link");
}
await userCredentials.user.reload();
}, 2000);
}
return <>{/* your sign up form */}</>;
}
As soon as user clicks the verification link, he will find your webpage redirects to <domain.name>/desired-link.
However, a bonus tip for you... Do not manipulate the action url. It's because by doing that, firebase.auth.currentUser.emailVerified will always return false. Meaning, user email would never be verified. It's because this action URL is responsible for email verification. So, instead of doing that, follow my example. This works for both localhost and your custom domain. Happy coding 🌹
You cannot have Firebase do a Authenticate then redirect unfortunately. The currently accepted answer on this is half-way there. By going into "Firebase -> Authentication -> Templates -> Email Address Verification -> Edit (aka. Pencil button)". You can then click on "Customize action URL" and insert any URL you want here.
Please note this URL you enter will not redirect you to the page after performing an email verification. All it will do is instead of generating the link <firebase email verification link>?mode=verifyEmail&oobCode=<code> it will instead direct you to <link you put in>?mode=verifyEmail&oobCode=<code>. Meaning that when a user lands on this page you will have to then handle the email verification yourself. Which means parsing out the query params, and sending this information along to Firebase in the back-end to verify the email in question. See the following for a potential on how to verify the email address: https://firebase.google.com/docs/reference/rest/auth#section-confirm-email-verification
More information about this can be found here: https://support.google.com/firebase/answer/7000714

Categories

Resources