Forgot Password Form using AWS Cognito - javascript

I am implementing a logic of forgot password using AWS Cognito. I am so far successful in changing the password using Prompts as given in the documentation. Here is the code
var username = document.getElementById('reset-pass').value;
var data = {
UserPoolId: _config.cognito.userPoolId,
ClientId: _config.cognito.clientId
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
// setup cognitoUser first
var cognitoUser = new AmazonCognitoIdentity.CognitoUser({
Username: username,
Pool: userPool
});
cognitoUser.forgotPassword({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
alert(err);
},
inputVerificationCode() {
var verificationCode = prompt('Please input verification code ' ,'');
var newPassword = prompt('Enter new password ' ,'');
cognitoUser.confirmPassword(verificationCode, newPassword, this);
}
});
My question is instead of using prompts, how can I confirm the user on next page. Example On the first page a user enter the email and mail is sent using the forgotPassword(). Now user is redirected to a new page. There i wanted to enter the code as well as the new password and call the cognitoUser.confirmPassword method.
What i tried is to create a delay interval and after entering the details it would trigger clear interval on button press.
function resetPassword() {
var username = document.getElementById('reset-pass').value;
var data = {
UserPoolId: _config.cognito.userPoolId,
ClientId: _config.cognito.clientId
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
// setup cognitoUser first
var cognitoUser = new AmazonCognitoIdentity.CognitoUser({
Username: username,
Pool: userPool
});
// call forgotPassword on cognitoUser
cognitoUser.forgotPassword({
onSuccess: function (result) {
alert("Mail Sent")
},
onFailure: function (err) {
console.log(err)
},
inputVerificationCode()
{
window.myVar = setInterval(function(){
console.log('check');
}, 10000);
var verificationCode = document.getElementById('code').value;
var newPassword = document.getElementById('fpass').value;
cognitoUser.confirmPassword(verificationCode, newPassword, this);
}
});
}
The HTML Part Of the code-
<div class="change">
<form>
<label>Enter Email ID</label>
<input type="email" id="reset-pass" required />
<br />
<div class="">Next</div>
</form>
</div>
div class="change-confirm">
<form>
<label>Enter Code</label>
<input type="number" id="code" required />
<br />
<label>Enter New Password</label>
<input type="password" id="fpass" required />
<br />
<div class=""> Reset</div>
</form>
</div>
But the above code never executed. Instead it stops execution after some time.
So my question is is there any way to delay the function call of cognitoUser.confirmPassword method? I do not want to use prompts instead get the email and code in a text field after mail is sent.

A little late to the party, but it can help someone else.
You can pass the congitoUser you have created to the state, and then use cognitoUser.confirmPassword(...) by retrieving the cognitoUser object from the state.

You should consider using the aws-amplify-react which provides a withAuthenticator higher-order component that provides a login flow with forgot password, mfa, etc. And it's maintained by a team of devs who work for AWS.
https://aws-amplify.github.io/docs/js/react#add-auth

Related

fuana database for static hosted sites

so i wrote this code and I am getting no errors in the console
the only error i get from the fauna server is An error occurred while logging in.
also i will change the secret key after this is awnsered for security reasons.
const client = new faunadb.Client({
secret: "fnAE7vAmHdAA1I7LvovMRWnGVVM2_sit_IrKDgnN"
});
async function signUp() {
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
try {
const result = await client.query(
q.Create(
q.Collection("users"),
{
data: {
email,
password
}
}
)
);
alert("Sign up successful! You can now log in.");
} catch (error) {
console.error(error);
alert("An error occurred while signing up.");
}
}
async function login() {
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
try {
const result = await client.query(
q.Get(
q.Match(
q.Index("users_by_email"),
email
)
)
);
if (result.password === password) {
alert("Login successful!");
} else {
alert("Incorrect email or password.");
}
} catch (error) {
console.error(error);
alert("An error occurred while logging in.");
}
}
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/faunadb"></script>
<script></script>
</head>
<body>
<h1>Sign Up</h1>
<form>
<label for="email">Email:</label>
<input type="email" id="email" required>
<br><br>
<label for="password">Password:</label>
<input type="password" id="password" required>
<br><br>
<button type="button" onclick="signUp()">Sign Up</button>
</form>
<h1>Login</h1>
<form>
<label for="email">Email:</label>
<input type="email" id="email" required>
<br><br>
<label for="password">Password:</label>
<input type="password" id="password" required>
<br><br>
<button type="button" onclick="login()">Login</button>
</form>
</body>
</html>
I've tried looking for errors in thr java script and tried playing around
with the fauna database itself
IMPORTANT
note about credentials in Fauna: using Fauna's built in Credentials support means you don't store the actual password, only the hashed password. This is also what enables Fauna's built in Login function, which returns a new user Token. Your current application provides all users with permissions to read every user, including every user's password, and that is very, very bad.
Your errors
I see that you are trying to access the password field by doing result.password. Notice that when you created the document, password is under the data field.
if (result.data.password === password) {
alert("Login successful!");
} else {
alert("Incorrect email or password.");
}
A better way
You should follow along with the User Authentication Tutorial.
It is my recommendation that you turn signup and login into UDFs and use a public key that has two permissions (and only two permissions):
call Function("signup")
call Function("login")
Then your application can use the public key to access these functions. The login function then gives you a separate Token, which you use to make a new Fauna Client. That Token should have whatever privileges a user should have (but no more).
Fauna Community Resources
Forums: https://forums.fauna.com/
Discord: https://discord.gg/2qXynEjn

Firebase onAuthStateChanged() triggering before retrieving name from signup form?

I'm creating a dashboard using vanilla HTML, CSS and JS, with Firebase as my backend. In my signup.html page, I have a form that allows users to input their name along with their email address and password. Upon signup, users are redirected to dashboard.html with their personalized content. Inside the dashboard, it has a spot where it displays their name.
The problem is it is not always getting the name from the form, and if it doesn't get the user's name from the signup form then it just doesn't have their name as I don't have a "add name" function in the dashboard. I suspect this is because of the way I use the onAuthStateChanged() inside signup.html.
The following is my signup page JS code:
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
window.location.replace('dashboard.html')
} else {
return
}
});
document.querySelector('#signup_btn').addEventListener("click", (e) => {
e.preventDefault();
var user_email = document.getElementById('user_email').value;
var user_pass = document.getElementById('user_pass').value;
var user_name = document.getElementById('user_name').value;
// Sign Up
firebase.auth().createUserWithEmailAndPassword(user_email, user_pass)
// Success
.then((userCredentials) => {
userCredentials.user.updateProfile({
displayName: user_name
})
})
// Errors
.catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode == 'auth/weak-password') {
alert('The password is too weak.');
} else {
alert(errorMessage);
}
console.log(error);
});
})
If it helps, here is the form from my signup.html page:
<form>
<h1>Sign Up</h1>
<!-- <h2>Log into your account using your email address</h2> -->
<label for="user_name">Name</label>
<input type="text" name="name" id="user_name">
<label for="user_email">Email Address</label>
<input type="text" name="email" id="user_email">
<label for="user_pass">Password</label>
<input type="password" name="Password" id="user_pass">
<button type="submit" id="signup_btn">Sign Up</button>
<p>Already have an account? Log In</p>
</form>
It seems like your onAuthStateChanged listener is being triggered before the write to the database has completed. This is the expected behavior for the API, but not what you want here.
Since you do want to use the onAuthStateChanged listener to navigate on page reload, the best I can think off is to turn off the listener when the user clicks the sign up button:
// 👇 store the unsubscribe function in a variable
var unsubscribe = firebase.auth().onAuthStateChanged(function (user) {
if (user) {
window.location.replace('dashboard.html')
} else {
return
}
});
document.querySelector('#signup_btn').addEventListener("click", (e) => {
e.preventDefault();
unsubscribe(); // 👈 turn off auth state listener
var user_email = document.getElementById('user_email').value;
var user_pass = document.getElementById('user_pass').value;
var user_name = document.getElementById('user_name').value;
// Sign Up
firebase.auth().createUserWithEmailAndPassword(user_email, user_pass)
// Success
.then((userCredentials) => {
return userCredentials.user.updateProfile({ // 👈 add a return
displayName: user_name
})
})
.then(() => {
window.location.replace('dashboard.html') // 👈 explicitly navigate here
})
As mentioned in the documentation,
onAuthStateChanged adds an observer for changes to the user's sign-in state.
When the user is logged in, it redirects your user to /dashboard before the updateProfile is resolved resulting in termination of that request.
I don't think you'll need an auth state listener on login page so try refactoring the code like this:
window.onload = function () {
if (firebase.auth().currentUser) window.location.replace("dashboard.html")
// Else stay on this page
// button click events here
}

Is it possible to retrieve user attributes from aws cognito in javascript on page load (Before login)?

I am using AWS cognito and successfully fulfilling all my requirements. However, there is a scenario is which I am struggling. I have an Auth code field along with username and password on login page and my requirement is to populate that auth code field before logging in.
I am successfully retrieving user attributes after login but in this case, I need to retrieve a user attribute before login to populate the input field.
My question is that is it possible to fetch a specific user attribute (Auth Code) before even login?
Below is the code for your reference that I am using to retrieve user attributes on clicking login button. Please have a look.
function signInButton() {
var authcode = document.getElementById("authcode").value;
var authenticationData = {
Username : document.getElementById("inputUsername").value,
Password : document.getElementById("inputPassword").value,
Authcode : document.getElementById("authcode").value,
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
var poolData = {
UserPoolId : _config.cognito.userPoolId, // Your user pool id here
ClientId : _config.cognito.clientId, // Your client id here
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username : document.getElementById("inputUsername").value,
Pool : userPool,
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
var userid = document.getElementById("inputUsername").value;
console.log('userid: ',userid)
if(authcode=='1234'){
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
var accessToken = result.getAccessToken().getJwtToken();
/////Getting User Attributes//////
AWS.config.update({region:'us-east-1'});
var params = {
AccessToken: accessToken
};
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
cognitoidentityserviceprovider.getUser(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} // an error occurred
else{
console.log(data);
} // successful response
})
/////// End /////////
if(accessToken!=null || accessToken!=''){
$.post("testapi.php", {userid: userid}, function(result){
console.log('result: ',result);
if(result.includes("accept")){
window.open("landing.php?status=Logged In","_self");
}else{
alert('Unauthorized User ID. Please try again with correct ID!')
}
});
}
console.log(accessToken);
},
onFailure: function(err) {
alert(err.message || JSON.stringify(err));
window.open("landing.php?status=Not Logged In","_self");
},
});
}else{
alert('Incorrect Authentication Code. Please try again');
}
}
Please suggest a possible solution.
Thank you

AWS Cognito forgotPassword returns request aborted

I'm build a React web client using AWS Cognito for user management. I'm using the amazon-cognito-identity-js library for this.
Login and sign up work fine.
Now, I'm unable to implement Use case 12: Starting and completing a forgot password flow for an unauthenticated user:
var cognitoUser = getCognitoUser({
Username : this.state.email //email from React component state
});
cognitoUser.forgotPassword({
onSuccess: function (result) {
console.log('call result: ' + result);
},
onFailure: function(err) {
console.log("failed", err);
alert(err);
},
inputVerificationCode() {
var verificationCode = prompt('Please input verification code ' ,'');
var newPassword = prompt('Enter new password ' ,'');
cognitoUser.confirmPassword(verificationCode, newPassword, this);
}
});
getCognitoUser
function getCognitoUser(userData) {
userData.Pool = getUserPool();
return new CognitoUser(userData);
}
getUserPool
function getUserPool() {
return new CognitoUserPool({
UserPoolId: config.cognito.USER_POOL_ID,
ClientId: config.cognito.APP_CLIENT_ID
});
}
The problem is that no matter what I type as an email, onFailure is called and I get a "RequestAbortedError: Request aborted" error.
Anybody knows what I'm doing wrong or how to get a better error message?
This actually works, I just forgot the event.preventDefault(); in the beginning of my click handler

Cognito confirmation code timeout

I'm registering my user on AngularJS with Cognito from Amazon WebService.
I have a very strange bug :
If users directly try to confirm them account with the verification code received by email they always have this error message : "ExpiredCodeException: Invalid code provided, please request a code again" eventhough them account is well confirmed in the user pool...
But If they register themselves and they wait few minutes to try to confirm them account its works perfectly !
This is how I confirm the verification code :
confirmRegistration: function(verificationCode, username, _poolData) {
var deferred = $q.defer();
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(_poolData);
var userData = {
Username : username,
Pool : userPool
};
cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.confirmRegistration(verificationCode, true, function(err, result) {
if (err) {
alert(err);
deferred.reject('confirmation failled.');
}
deferred.resolve('successfully confirmed.')
});
return deferred.promise;
},
How could I fixe it ?
Where is from this problem ?
Do there is a timeout to set somewhere ?

Categories

Resources