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 ?
Related
I have a project, a simple login form hooked to nodejs which is connected to MongoDB as the database.
relevant to this question
I use pure javascript, no jquery
my main aim in this project is to display error in the form without reloading the page (through a model) but if the information is correct or a user is found, the user is redirected to the profile page => now this is where the problem is.
this is my client request
// *the myModel is a bootstrap function that is used to notify users for error*
const myModel = new bootstrap.Modal(document.querySelector('.modal'), {
focus : true
})
document.querySelector("form").addEventListener("submit", function(e){
e.preventDefault()
data = {
username : document.forms[0].username.value,
password : document.forms[0].password.value
}
fetch("/login", {
method: "POST",
headers : { "content-Type": "application/json" },
body : JSON.stringify(data)
}).then(async(response)=>{
data = await response.json()
if(data.err){
console.log(data.redirect)
document.querySelector(".modal-body").innerText = data.err
myModel.show()
}else{
window.location.replace(data.redirect)
}
})
.catch(err=>{
document.querySelector(".modal-body").innerText = err.message
myModel.show()
})
})
this is my server-side code/response
.post(function(req,res){
console.log(req.body)
if(req.body.username.trim() && req.body.password.trim()){
const data = req.body
userCollection.findOne({username:data.username},function(error,back){
if(error){
console.log(error.message)
}else{
if(back){
console.log(back)
if(back.password === data.password){
res.redirect("/profile")
}else{
res.json({err : "password or username wrong, try again"})
res.end()
}
}
else{
console.log("no user found, check your inputs again")
res.json({err : "no user found, check your inputs again"})
res.end()
}
}
})
}else{
res.json({err:"username or password empty"})
}
everything works fine except when a user is found and the passwords match and I'm trying to redirect the user, the client-side request .catch keeps sending me an error "unexpected token < in json at position 4"
but if I change the res.redirect to maybe res.json("your account has been found") then it works fine without any error.
i've been stuck here for a day+ if you know how i will combat this, help for the sake of my mental health " haha
~~
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
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
First a little background:
I am working on an seperate mobile application that is connected with the main app. The connection is succesfully initiated and I can retrieve all collections, through subscriptions:
Remote = DDP.connect('http://localhost:3000/');
Meteor.users = new Meteor.Collection('users', {
connection: Remote
});
Remote.subscribe('users', true);
Now I want to make sure users can log in through the interface of the second app. After installing the accounts-password and the meteor-ddp-login package, I should be able to authenticate with the main app by using the next piece of code in the client side.
var Remote = DDP.connect('http://localhost:3000/');
DDP.loginWithPassword(Remote, {
username: username
}, password, function(error) {
if (!error) {
console.log(username + " is logged in!");
} else {
console.log(error);
}
});
Well, so far so good. No errors appear and the console logs a success message. Now the question comes:
How can I retrieve the user object of the user who just logged in.
I've set up several publish functions in the main app, but the user data does not become available to the client in the second app (other collections work fine, but Meteor.user() is undefined).
And also: How can I authenticate users who login with Facebook/Google/Twitter
Came across this, I had a similar need recently. Following code works in Meteor version 1.2.0.2
if (Meteor.isClient) {
Meteor.startup(function(){
//Seems that without this, on page refresh, it doesn't work.
//COMMENT: Ideally this should not be needed if the core takes care of this use case of a different connection for Accounts
//hack block 1***********
var token = Accounts._storedLoginToken();
if(token) {
Meteor.loginWithToken(token, function(err){
// this is going to throw error if we logged out
if(err)
console.log(err);
else
console.log('loginWithToken');
});//loginWithToken
}
//hack block 1***********
});//startup function
var connection = DDP.connect("http://localhost:3060");
Accounts.connection= connection;
//COMMENT: Ideally this should not be needed if the core takes care of this use case of a different connection for Accounts
//hack block 2***********
Accounts.users = new Meteor.Collection('users', {
connection: connection
});
//hack block 2***********
Tracker.autorun(function () {
//No code which directly affects the functionality. Just for testing
console.log(Meteor.user());
Accounts.connection.call('user',function(err,result){
if(err)
console.log(err);
if(result){
console.log(result);
if(result._id === Meteor.user()._id){
console.log("Server and client shows that the same user has logged in");
} else {console.log("Server and client shows different users");}
}
})
});
Template.register.events({
'submit #register-form' : function(e, t) {
e.preventDefault();
var email = t.find('#account-email').value
, password = t.find('#account-password').value;
Accounts.createUser({email:email,password:password}, function(err,result){
if (err) {
// Inform the user that account creation failed
console.log(err);
} else {
// Success. Account has been created and the user
// has logged in successfully.
console.log("registered user");
console.log('response is '+ result);
console.log(Meteor.user());
}
});//createUser
return false;
}
});//register
Template.login.events({
'submit #login-form': function(e,t){
e.preventDefault();
var email = t.find('#login-email').value
, password = t.find('#login-password').value;
Meteor.loginWithPassword(email, password, function(err){
if (err)
console.log(err);
else
// The user has been logged in.
console.log('logged in successfully');
});
return false;
}
});//login
Template.statusloggedin.events({
'click #logout': function(e,t){
e.preventDefault();
Meteor.logout();
return false;
}
});//logout
}
I've written my own custom authentication to work with our corporate OAuth solution. This results in an OAuth access and refresh token being sent to me. I can then store these tokens in the user collection of the Meteor database but when I want to perform reauthentication I need to be able to find the right session to be able to locate which OAuth token I should use for refreshing it, if required. Since the user can login from multiple devices, this complicates matters.
This is the code I use to store the tokens and send result on the server-side:
var userId = null;
var user = Meteor.users.findOne({username: userName});
if (!user) {
userId = Meteor.users.insert({username: userName});
} else {
userId = user._id;
}
logger.info("User logged in: " + userId);
var initToken = Accounts._generateStampedLoginToken();
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
// Need way to bind oath.loginTokens with Meteor resume token
Meteor.users.update(userId,
{$push: {'services.oauth.loginTokens': token}}
);
var rslt = {
userId: userId
};
return(rslt);
And this is the resulting record in the DB:
"services" : {
"oauth" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.635Z"),
"hashedToken" : "ErcosEo9rD+IuT3EyFb3DFS8Bf0enwLzkCIf/nP1JFE=",
"accessToken" : "bhafr3WBDS67EmZ9hFE20af83BJRPFQQS8NGpMlSH6NHVCOiTeTuTJ",
"refreshToken" : "enOAFkBcxB88FlATUh2m0E5NLLG0y8AojyIH5gItnJXdU6",
"ttl" : 3600
}
]
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.637Z"),
"hashedToken" : "uhRZpGdBHnAVKvgBEm7oSWsdflOGRI2YrR9Q21iqjzp+Xc="
}
]
}
},
"username" : "lous"
As you can see from what's above, I need to key off of one of the token values to find the right oauth information to do a possible refresh. On the client side I then do what's shown below, but the problem is that the token returned in validateResult is not the same token that is being stored in the DB, so I have no way to track which session is mine.
Template.login.events({
'submit #login-form': function(e,t) {
e.preventDefault();
var id = t.find('#login-id').value,
password = t.find('#login-password').value;
var req = {id: id, password: password};
Accounts.callLoginMethod({
methodArguments: [req],
validateResult: function (result) {
var token = result.token;
window.localStorage.setItem('token', token);
subscribeToRequests();
$.mobile.changePage('#landingPage', {transition: 'slidefade'});
},
userCallback: function(error) {
if (error) {
console.log("Error: " + error.message);
alert("Login Failure");
}
}
});
return false;
}
});
Why would the token not be the same? Any recommendations on how to address this? Then once I do have the token stored client side, does Meteor provide an out-of-the-box way to test the token's validity? Here's the findUser method I'm using to attempt to do that:
Meteor.methods({
findUser: function(token) {
var user = null;
var hashedToken = Accounts._hashLoginToken(token);
if (this.userId) {
//TODO need user object to include token to do TTL check and reauth if necessary
user = Meteor.users.findOne({_id:this.userId});
var result = refreshUser(user);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
}
});
In your findUser method, you can call Accounts._getLoginToken(this.connection.id) to get the current login token for the connection. You can then look up the OAuth access token associated with this value.
As for your original question of why result.token on the client is different from what's in the database: I think you're comparing the unhashed token (result.token) to the hashed token stored in the database. If that's the case, you can pass result.token to the server and pass it through Accounts._hashLoginToken before looking it up in the database.
Does that make sense?
Here's how I ended up aligning my OAuth tokens with the Meteor session token.
I created the following Meteor.methods on the server-side and my client just calls the updateToken in the validateResult of my Accounts.callLoginMethod so my oauth tokens can be found by the method #emily describes in her answer.
It calls reauthenticateUser whenever the app starts up or is refreshed and finally, it calls logoutUser when the user logs our or the session timeout expires.
updateToken: function() {
// Update oauth hash token with correct hashed token
var user = Meteor.users.findOne({'_id': this.userId});
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Get last element for OAuth array (safely presuming the last one is the last oauth from current call stack) and update hashedToken
var oauthObj = _.last(user.services.oauth.loginTokens);
Meteor.users.update({'services.oauth.loginTokens': {$elemMatch: {hashedToken: oauthObj.hashedToken}}}, {$set: {'services.oauth.loginTokens.$.hashedToken': hashedToken}});
},
reauthenticateUser: function() {
var user = null;
if (this.userId) {
var hashedToken = Accounts._getLoginToken(this.connection.id);
user = Meteor.users.findOne({$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]});
// Get specific oauthTokens (keep in mind multiples per client)
var oauthTokens = _.findWhere(user.services.oauth.loginTokens, {'hashedToken': hashedToken});
var result = refreshUser(this.userId, user.username, oauthTokens);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
},
logoutUser: function() {
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Remove orphaned Oauth tokens
Meteor.users.update(
{$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]},
{$pull: {'services.oauth.loginTokens': {'hashedToken':hashedToken}
}});
return true;
}
Once I had this in place, it was easy for me to update the oauth tokens once they were refreshed or to remove them once the user logged out.
I'm not meteorJS developer, but I'll try to suggest the resolution of problem.
install meteor-cookies using npm install meteor-cookies.
and then:
var initToken = Cookie.get('initToken');
if(!initToken) {
initToken = Accounts._generateStampedLoginToken();
Cookie.set('initToken', initToken, {days: 30});
}
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
OR:
var token = Cookie.get('token');
if(!token) {
var initToken = Accounts._generateStampedLoginToken();
token = Accounts._hashStampedToken(initToken);
Cookie.set('token', token, {days: 30});
}
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
maybe there are errors in my additions but I think You've understood the trick. (: