Aws amplify google SSO, sign in is not persisted in local storage - amazon-cognito

The app is built with react.
I am having some trouble making sure the user stays loggedIn after signing in via Google SSO. Following are my relevant imports
import { Amplify, Auth, Hub, Cache } from "aws-amplify";
import awsExports from "./aws-exports";
Hi, I am using the following code. To listen to sign in events. The Sign in is successful, and stores all the relevant info in the local Storage for the tab that was used to log in. However, if I open another tab the information is not there, and therefore the currentAuthenticatedUser returns unauthenticated.
If I use a username, password log in, the data persists across tabs.
I am using ImplicitGrant, with Google.
useEffect(() => {
// Side Effect
console.log("not app use effect");
// fetchDevices();
if (!authenticated) {
console.log("fetching session", Cache.getItem("userSession"));
console.log("getting my item", localStorage.getItem("myItem"));
Auth.currentAuthenticatedUser({
bypassCache: false, // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data
})
.then((user) => {
console.log("got suer datal", user);
if (user?.username) {
console.log("usernname exists", user.username.startsWith("google"));
if (user.username.startsWith("google")) {
console.log("modifying the username");
user.username = user?.attributes.email.split("#")[0];
}
console.log("user autheticatd", user);
setAuthenticated(true);
// rememberDevice();
setCurrentActiveUser(user);
store.dispatch(
getUserExistingAPIKey(user?.signInUserSession?.idToken?.jwtToken)
);
store.dispatch({
type: SET_ID_TOKEN,
payload: user?.signInUserSession?.idToken?.jwtToken,
});
// getExistingUserAPIKey(user?.signInUserSession?.idToken?.jwtToken);
}
})
.catch((e) => {
console.log("the first login failed");
console.log(e);
});
}
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
switch (event) {
case "signIn":
console.log("sign in event", data);
setAuthenticated(true);
setCurrentActiveUser(data);
store.dispatch(
getUserExistingAPIKey(data?.signInUserSession?.idToken?.jwtToken)
);
store.dispatch({
type: SET_ID_TOKEN,
payload: data?.signInUserSession?.idToken?.jwtToken,
});
rememberDevice();
Auth.currentAuthenticatedUser({
bypassCache: true, // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data
})
.then((user) => {
console.log("got suer datal", user);
if (user?.username) {
console.log(
"usernname exists",
user.username.startsWith("google")
);
if (user.username.startsWith("google")) {
console.log("modifying the username");
user.username = user?.attributes.email.split("#")[0];
}
console.log("user autheticatd", user);
setAuthenticated(true);
rememberDevice();
setCurrentActiveUser(user);
store.dispatch(
getUserExistingAPIKey(
user?.signInUserSession?.idToken?.jwtToken
)
);
store.dispatch({
type: SET_ID_TOKEN,
payload: user?.signInUserSession?.idToken?.jwtToken,
});
// getExistingUserAPIKey(user?.signInUserSession?.idToken?.jwtToken);
}
})
.catch((e) => {
console.log("the first login failed");
console.log(e);
});
break;
case "signUp":
console.log("sign up event");
setAuthenticated(true);
setCurrentActiveUser(data);
break;
case "signOut":
console.log("sign out event");
// setUser(data);
setAuthenticated(false);
setCurrentActiveUser(null);
break;
case "cognitoHostedUI":
console.log("cognito hosted ui event", data);
Auth.currentSession()
.then((session) => {
// Save the session info to the cache
console.log("session", session);
Cache.setItem("userSession", session);
localStorage.setItem("myItem", session);
})
.catch((err) => {
console.log("err", err);
});
Auth.currentAuthenticatedUser({
bypassCache: true, // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data
})
.then((user) => {
console.log("updated user", user);
let token = data?.signInUserSession?.idToken?.jwtToken;
Auth.federatedSignIn(
"google",
{
token,
expires_at: 1000 + new Date().getTime(), // the expiration timestamp
},
user
)
.then((cred) => {
// If success, you will get the AWS credentials
console.log("cred", cred);
return Auth.currentAuthenticatedUser();
})
.then((user) => {
// If success, the user object you passed in Auth.federatedSignIn
console.log("fetched user", user);
setAuthenticated(true);
// rememberDevice();
setCurrentActiveUser(user);
store.dispatch(
getUserExistingAPIKey(
user?.signInUserSession?.idToken?.jwtToken
)
);
store.dispatch({
type: SET_ID_TOKEN,
payload: user?.signInUserSession?.idToken?.jwtToken,
});
})
.catch((e) => {
console.log(e);
});
})
.catch((e) => {
console.log("error", e);
});
break;
case "customOAuthState":
console.log("custom oauth event", data);
setAuthenticated(true);
setCurrentActiveUser(data);
break;
case "signIn_failure":
console.log("user sign in failed", data);
break;
case "tokenRefresh":
console.log("token refresh succeeded");
break;
case "tokenRefresh_failure":
console.log("token refresh failed");
break;
case "autoSignIn":
console.log("auto sign in");
break;
case "autoSignIn_failure":
console.log("auto sign in failed");
break;
case "cognitoHostedUI_failure":
console.log("cognito hosted ui failed");
Auth.federatedSignIn({ provider: "Google" })
.then(async (cred) => {
// If success, you will get the AWS credentials
console.log(cred);
Auth.currentAuthenticatedUser({
bypassCache: false, // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data
})
.then((user) => {
console.log("got suer datal", user);
if (user?.username) {
console.log(
"usernname exists",
user.username.startsWith("google")
);
if (user.username.startsWith("google")) {
console.log("modifying the username");
user.username = user?.attributes.email.split("#")[0];
}
console.log("user autheticatd", user);
setAuthenticated(true);
rememberDevice();
setCurrentActiveUser(user);
store.dispatch(
getUserExistingAPIKey(
user?.signInUserSession?.idToken?.jwtToken
)
);
store.dispatch({
type: SET_ID_TOKEN,
payload: user?.signInUserSession?.idToken?.jwtToken,
});
// getExistingUserAPIKey(user?.signInUserSession?.idToken?.jwtToken);
}
})
.catch((e) => {
console.log("the first login failed");
console.log(e);
});
})
.catch((e) => {
console.log("the second login failed");
console.log(e);
});
break;
case "customState_failure":
console.log("custom state failure", event, data);
break;
default:
console.log("DEFAUL CASE", event, data);
break;
}
});
return unsubscribe;
});
I receive a cognitoHostedUI event after signingIn. I tried to store data manually but it never persists when I open a new tab.
any help would be appreciated, seriously considering, getting off of cognito/amplify.

Related

facebook login working on development mode or server mod, when create a build, it's not working on any devices. react native app

feature unavailable facebook login in currently unavailable for this app, since we are updating additionl details for this app. please try again later
working only on my system and device, not working in others,
how to resolve this issue,please help
FacebookSignIn = async () => {
// Attempt login with permissions
try {
const result = await LoginManager.logInWithPermissions(['public_profile', 'email']);
console.log("fb login", result)
if (!result.isCancelled) {
await AccessToken.getCurrentAccessToken()
.then(async res => {
console.log("token", res);
// Create a Firebase credential with the AccessToken
const facebookCredential = auth.FacebookAuthProvider.credential(res.accessToken);
console.log("token", res);
// Sign-in the user with the credential
this.setState({ loder: true })
await auth().signInWithCredential(facebookCredential)
.then(response => {
console.log("Login Data", response);
const data = {
"name": response.additionalUserInfo.profile.first_name,
"email": response.additionalUserInfo.profile.email,
"user_type": 0
}
console.log(data);
fetchPostMethod('/facebook-sign-up', data)
.then(async response => {
this.setState({ loder: false })
if (response.status == 200) {
if (response.data.user_type == 0) {
try {
let user = JSON.stringify(response?.data?.user_type)
await AsyncStorage.setItem('SignINToken', response?.data?.token);
await AsyncStorage.setItem('UserType', user);
this.logmodl();
} catch (e) {
console.log("Login error", e)
}
} else {
this.user();
}
console.log("SignIn Successful", response);
} else {
this.field();
}
})
.catch(response => {
this.setState({ loder: false })
console.log("SignIn faild", response.message);
})
this.setState({ FacebookUserInfo: response });
})
.catch(error => {
console.log('Login Data Error', error);
})
})
.catch(error => {
console.log('Something went wrong obtaining access token ', error);
})
}
} catch (error) {
console.log("ERROR WHILE LOGIN! ", error);
}
}
feature unavailable facebook login in currently unavailable for this app, since we are updating additionl details for this app. please try again later
working only on my system and device, not working in others,
how to resolve this issue,please help
Pay attention! For enable Facebook login for other users you need visit the Facebook developer site
and enable work mode for application, moving this switch

Express passport.authenticate() not working properly

I'm having some issues with setting up passport. The information gets to the console.log(req.body) before passport.authenticate and then console.log(req.user) will return undefined afterwards. I will not hit the console.log inside of passport.use() function that is after the new LocalStrategy code. This does not though an error, nothing seems to happen. It will just enter the second if statement if(!user) and return me the status and error I outlined there. I have been trying to debug this for awhile and alas I'm no longer sure what the deal is.
this is what my auth file looks like
router.post("/login", (req, res, next) => {
console.log(req.body);
passport.authenticate("local", function (err, user, info) {
//console.log(req);
//console.log(user);
if (err) {
//console.log("cp1");
return res.status(400).json({ errors: err });
}
if (!user) {
return res.status(400).json({ errors: "No user found" });
}
req.logIn(user, function (err) {
console.log("cp1");
if (err) {
//console.log("cp3");
return res.status(400).json({ errors: err });
}
return res.status(200).json({ success: `logged in ${user.id}` });
});
})(req, res, next);
});
and this is what my passport.js file looks like
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(null, user);
});
});
passport.use(
new LocalStrategy((email, password, done) => {
console.log(`${email} , ${password}`);
db.User.findOne({ email: email })
.then((user) => {
if (!user) {
} else {
if (user.password === password) {
return done(null, user);
} else {
return done(null, false, { message: "Wrong Password" });
}
}
})
.catch((err) => {
return done(null, false, { message: err });
});
})
);
passport.initialize();
passport.session();
There is no such thing as req.user, I suppose you meant req.body.user or req.body.username depending on the JSON you send in the request.
I advice you to look at my repo below where I recently successfuly implemented Passport in Express:
https://github.com/fromb2b/saas

Can someone please tell me where can i write my bcrypt-hashing function?

exports.postLogin = (req, res) => {
let { email, pass } = req.body;
console.log(email);
User.findOne({ email }, (err, result) => {
console.log(email, pass, result.pass);
if (err) {
res.json({ status: 'failed', message: err });
} else if (!result) {
res.json({ status: 'failed', message: 'email or password are wrong' });
} else {
bcrypt.compare(pass, result.pass).then(async (isPassCorrect) => {
if (isPassCorrect) {
const token = await signToken(result.id);
res.json({
status: 'success',
message: 'you logged in !!',
token,
});
} else res.json({ status: 'failed', message: 'email or password are wrong!' });
});
}
});
};
Your quetsion is not really clear about what you are trying to do, so I'm guessing into the black.
If I get you right, you are looking for the right place in order to hash a password before it gets saved, so you can use bcrypt.compare() on the encrypted password, is that right?
If yes, you could use mongooses pre-hook to hash the password before mongoose actually saves a document. To accomplish this add this to your model file
User.pre('save', async function (next) {
await bcrypt.genSalt(12).then(async salt => {
this.password = await bcrypt.hash(this.password, salt).catch(err => {
return next(err)
})
}).catch(err => {
return next(err)
})
})

React-Native-FBSDK login doesn't return email

I'm trying to use the default <'LoginButton ... > for login in the app through Facebook login, but I can't manage to get the user's email.
This is my button:
<LoginButton
publishPermissions={["email"]}
onLoginFinished={
(error, result) => {
if (error) {
alert("Login failed with error: " + error.message);
} else if (result.isCancelled) {
alert("Login was cancelled");
} else {
alert("Login was successful with permissions: " + result.grantedPermissions)
}
}
}
onLogoutFinished={() => alert("User logged out")}
/>
And this is how i try to get the user's details:
async FBGraphRequest(fields, callback) {
const accessData = await AccessToken.getCurrentAccessToken();
console.log("token= ", accessData.accessToken )
// Create a graph request asking for user information
const infoRequest = new GraphRequest('/me', {
accessToken: accessData.accessToken,
parameters: {
fields: {
string: fields
}
}
}, this.FBLoginCallback.bind(this));
// Execute the graph request created above
new GraphRequestManager().addRequest(infoRequest).start();
}
async FBLoginCallback(error, result) {
if (error) {
this.setState({
showLoadingModal: false,
notificationMessage: "facebook error"
});
} else {
// Retrieve and save user details in state. In our case with
// Redux and custom action saveUser
this.setState({
id: result.id,
email: result.email,
name: result.name
});
console.log("facebook login",result)
}
}
The console.log("facebook login",result) line returns me only the account name and id, but there is no field for te email...
What am I doing wrong?
PS.: I've also tryed to use a "custom function", but it doesn't work too (for the email, the login worked and i get only the user details like name and id):
async facebookLogin() {
// native_only config will fail in the case that the user has
// not installed in his device the Facebook app. In this case we
// need to go for webview.
let result;
try {
this.setState({showLoadingModal: true});
LoginManager.setLoginBehavior('NATIVE_ONLY');
result = await LoginManager.logInWithReadPermissions(['public_profile', 'email']);
} catch (nativeError) {
try {
LoginManager.setLoginBehavior('WEB_ONLY');
result = await LoginManager.logInWithReadPermissions(['email']);
} catch (webError) {
// show error message to the user if none of the FB screens
// did not open
}
}
console.log("facebook result 1: ", result)
// handle the case that users clicks cancel button in Login view
if (result.isCancelled) {
this.setState({
showLoadingModal: false,
notificationMessage: I18n.t('welcome.FACEBOOK_CANCEL_LOGIN')
});
} else {
// Create a graph request asking for user information
this.FBGraphRequest('id, email, name', this.FBLoginCallback);
}
}
.
.
.
<LoginButton
publishPermissions={["email"]}
onPress={
this.facebookLogin()
}
onLogoutFinished={() => alert("User logged out")}
/>
this are the field request by the app. I need to insert also the user's Email:
!!!RESOLVED!!!
the <'LoginButton ...> props for the permission is "permissions", not "readPermission"...
so the button code is:
<LoginButton
permissions={['public_profile', 'email', 'user_birthday', ]}
onClick={this.facebookLogin}
/>
// imports
import {
Settings,
AccessToken,
LoginManager,
AuthenticationToken,
Profile,
GraphRequest,
GraphRequestManager,
} from 'react-native-fbsdk-next';
//put this lines in useEffect
Settings.setAppID('2920461228193006');
Settings.initializeSDK();
LoginManager.setLoginBehavior('web_only');
// put this method on button press
LoginManager.logInWithPermissions(['public_profile', 'email'])
.then(async data => {
if (!data.isCancelled) {
console.log(data, 'this is data');
if (Platform.OS === 'ios') {
let token =
await AuthenticationToken.getAuthenticationTokenIOS();
console.log(token, 'ios token');
} else {
let token = await AccessToken.getCurrentAccessToken();
console.log(token, 'android token');
}
const infoRequest = new GraphRequest(
'/me?fields=email,name,first_name,last_name',
null,
(err, res) => {
console.log({err, res}, 'this is');
if (Object.keys(res).length != 0) {
doSocialLogin({
registerBy: 2,
token: res.id,
user: {
firstName: res.first_name,
email: res.email,
lastName: res.last_name,
},
});
}
},
);
new GraphRequestManager().addRequest(infoRequest).start();
}
})
.catch(err => {
console.log(err, 'this is fb error');
});

undefined jwt token react/express

I am implementing a JWT authentication on a login/registration system. When there is a successful login/registration I am setting a user token in localStorage.
Problem is when I check my localStorage the user key is present but the value is undefined. I think the issue might be in my axios post or in my express file but I can't quite figure it out.
// my action creator
export function login(user, history) {
return async (dispatch) => {
axios.post('/api/login', { user })
.then(res => {
dispatch({ type: AUTHENTICATED });
localStorage.setItem('user', res.data.token);
history.push('/');
})
.catch((error) => {
dispatch({
type: AUTHENTICATION_ERROR,
payload: 'Invalid email or password'
});
});
};
}
The data is reaching my api correctly. The item is being set but the value res.data.token is undefined.. Below is my express file
// login.js (/api/login)
router.post('/', function(req, res) {
var email = req.body.user.email;
var password = req.body.user.password;
// TODO: create db file and import connection
var connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "dbname",
port: 3307
});
connection.connect(function(err) {
if(err) {
console.log(err);
} else {
connection.query("SELECT ID, Password FROM Users WHERE Email = ?", [email], function(err, result) {
if(err) {
console.log('Could not find account');
res.send(err);
} else {
var id = result[0].ID;
bcrypt.compare(password, result[0].Password, function(err, result) {
if(result) {
console.log(id);
res.json({ id });
} else {
console.log('Incorrect password');
}
});
}
});
}
});
});
Since the res.data.token in my action creator is returning undefined does that mean the response in my express file ( res.json([id]) ) is just returning defined?
You are not sending the response properly.
res.json([id]); Its just sending the array of id. That's why res.data.token is undefined. as data does not contain an object.
Send proper object like:
res.json({id});