setting state not setting in React - reactjs

I have the following code
this.setState({loading: true}, () => {
if (googleUser && googleUser.profileObj) {
app.auth().signOut();
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
var unsubscribe = app.auth().onAuthStateChanged(firebaseUser => {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
if (!this.isUserEqual(googleUser, firebaseUser)) {
// Build Firebase credential with the Google ID token.
var credential = firebase.auth.GoogleAuthProvider.credential(
googleUser.getAuthResponse().id_token);
// Sign in with credential from the Google user.
app.auth().signInWithCredential(credential).catch(error => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// The email of the user's account used.
var email = error.email;
// The firebase.auth.AuthCredential type that was used.
var credential = error.credential;
this.setState({error: errorMessage, loading: false})
}).then(() => {
app.auth().onAuthStateChanged((user) => {
if (user) {
user.getIdToken().then(idToken => {
// Session login endpoint is queried and the session cookie is set.
// CSRF protection should be taken into account.
const csrfToken = Utils.getCookie('csrfToken');
this.postIdTokenToSessionLogin('/auth/session-login', idToken, csrfToken, 'google', googleUser.profileObj.googleId);
});
} else {
this.setState({error: "There was an error", loading: false});
}
});
})
} else {
this.setState({error: "You are already signed in.", loading: false});
}
});
}
});
The code is not working, it's not setting loading to true and not re-rendering before invoking the callback function in setState.
Does anyone know what's going on?

Related

Persist auth state in react/react native for Firebase

I am using react native for an ios app and firebase for authentication. Every time I leave the app and come back, it asks for a login. I want to persist the firebase login but don't really know where to put it.
I know I need to put this in:
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
I have the following signIn function that runs when the login button is pressed on the signInScreen:
const signIn = async () => {
setLoading(true);
try {
await firebase.signIn(email, password);
const uid = firebase.getCurrentUser().uid;
const userInfo = await firebase.getUserInfo(uid);
const emailArr = userInfo.email.split("#");
setUser({
username: emailArr[0],
email: userInfo.email,
uid,
isLoggedIn: true,
});
} catch (error) {
alert(error.message);
} finally {
isMounted.current && setLoading(false);
}
};
I have the following signIn stuff in my firebaseContext:
const Firebase = {
getCurrentUser: () => {
return firebase.auth().currentUser;
},
signIn: async (email, password) => {
return firebase.auth().signInWithEmailAndPassword(email, password);
},
getUserInfo: async (uid) => {
try {
const user = await db.collection("users").doc(uid).get();
if (user.exists) {
return user.data();
}
} catch (error) {
console.log("Error #getUserInfo", error);
}
},
logOut: async () => {
return firebase
.auth()
.signOut()
.then(() => {
return true;
})
.catch((error) => {
console.log("Error #logout", error);
});
},
};
Where do I put the persist code I listed above from the docs?
Thanks!
When do you check if someon is signed in or not?
From the code shown it looks like you check it manuelly by calling currentUser. You have to consider that the persistance of auth state is asynchronous. That means if you call currentUser on auth before the localy saved auth state is loaded you would get there null and thing that the user is not signed in.
To get the auth state Firebase recommend to use the onAuthStateChanges event listener. With that you can listen to auth state changes no matter if you logged in or the persistet auth state is loaded.
The usage is very simple:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
That is the reson I asked where you check if someon is signed in or not. If I could see that code I could help you adopt it to use that event listener.

Login to MS Graph with React and MSAL fails with no errors on console

I'm trying to use MSAL and React to login to MSGraph. I get the popup to authenticate when I call userAgentApplication.loginPopup({propt: "select_account", scopes: config.scopes})
After entering my login information, it appears that I authenticated but when I try to make a request the login popup continues to display as if I didn't authenticate already. I get no errors on the console.
I refresh the page and check localStorage and see msal.error = invalid_state_error
I'm using MSAL version v1.4.6
Here is my code
ContextualMenu.js
import { msgraph } from './actions/graphAction';
const graph = useSelector((state) => state.graph);
const userAgentApplication = new UserAgentApplication({
auth: {
clientId: config.appId,
redirectUri: config.redirectUri
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: true
}
});
const getUserProfile = async () => {
try {
let accessToken = await userAgentApplication.acquireTokenSilent({
scopes: config.scopes
});
if (accessToken) {
let user = await getUserDetails(accessToken);
let uu = {
displayName: user.displayName,
email: user.mail || user.userPrincipalName,
givenName: user.givenName,
surname: user.surname
}
dispatch(msgraph(true, uu, null));
}
} catch (err) {
console.log(err);
}
};
const msLogin = async () => {
try {
await userAgentApplication.loginPopup({
prompt: "select_account"
});
getUserProfile();
}
catch (err) {
console.log('failed', err);
}
};
const emailFiles = () => {
setRootClassName('close');
if (graph.isAuthenticated) {
checkSelectedFile();
return false;
}
msLogin();
}
After loginPopup is called it never gets to getUserProfile and doesn't error either.
Please any help is appreciated

How do I keep the user logged into firebase after refresh in React.JS

There is a similar question here, the suggested answer doesn't seem to work for me.
Here is how I am using firebase mobile sign in for sign in ReactJS. I am also setting auth state persistence on sign in (see below code).
However when I refresh the page after sign in the user object disappears i.e "User is not signed in" message gets printed in componentDidMount.
What could I be doing wrong ?
class SignInScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
isSignedIn: false,
};
}
// Configure FirebaseUI.
uiConfig = {
// Popup signin flow rather than redirect flow.
signInFlow: "popup",
signInOptions: [
{
provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID,
defaultCountry: "US",
},
],
callbacks: {
// Avoid redirects after sign-in.
signInSuccessWithAuthResult: () => false,
},
};
// Listen to the Firebase Auth state and set the local state.
componentDidMount() {
this.unregisterAuthObserver = firebase.auth().onAuthStateChanged((user) => {
this.setState({ isSignedIn: !!user });
if (user != null) {
this.setAuthPersistence(); // Setting state persistence here
}
});
if(firebase.auth().currentUser){
console.log("User is already signed in")
}else{
console.log("User is not signed in")
}
}
setAuthPersistence = () => {
firebase
.auth()
.setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then(function() {
console.log("Local persistence set");
})
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log("Local persistence has not been set");
});
};
// Make sure we un-register Firebase observers when the component unmounts.
componentWillUnmount() {
this.unregisterAuthObserver();
}
render() {
//Displaying firebase auth when user is not signed in
if (!this.state.isSignedIn) {
return (
<div>
<StyledFirebaseAuth
uiConfig={this.uiConfig}
firebaseAuth={firebase.auth()}
/>
</div>
);
}
return <Redirect to="/signedInUser" />;
}
}
export default SignInScreen;
Same as in the answer you linked, your if(firebase.auth().currentUser) runs before Firebase has asynchronously refreshed the authentication state, and thus before the user is signed in again.
Any code that needs to respond to the authentication state, needs to be in the onAuthStateChanged callback. So:
componentDidMount() {
this.unregisterAuthObserver = firebase.auth().onAuthStateChanged((user) => {
this.setState({ isSignedIn: !!user });
if (user != null) {
this.setAuthPersistence(); // Setting state persistence here
}
if(firebase.auth().currentUser){
console.log("User is already signed in")
}else{
console.log("User is not signed in")
}
});
}

AWS Cognito completeNewPasswordChallenge calls onFailure method but the user is confirmed in AWS Console

I'm using AWS Cognito Javascript SDK in a react application. I have a user that was created in the AWS Console by an admin, and when the user is logged in for the first time they have to reset their password. I go through the newPasswordRequired flow, and when I call the completeNewPasswordChallenge function with the parameters, the onFailure callback is ran. When I log the error I get, {code: "UnknownError", message: "Unknown error"}. However, when I check the AWS Console, the user in the user pool is changed from FORCE_CHANGE_PASSWORD to CONFIRMED.
My code is:
class LoginScreenContainer extends Component {
constructor(props) {
super(props);
this.state = {
isInvalidForm: null,
isFirstLogin: false,
user: null,
userAttr: null
}
this.onFormSubmission = this.onFormSubmission.bind(this);
this.updatePassword = this.updatePassword.bind(this);
}
onFormSubmission = (username, password) => {
const poolData = {
UserPoolId : AWSConfig.cognito.USER_POOL_ID,
ClientId : AWSConfig.cognito.APP_CLIENT_ID
}
const userPool = new CognitoUserPool(poolData);
const userData = {
Username: username,
Pool: userPool
}
const cognitoUser = new CognitoUser(userData);
const authenticationData = {
Username : username,
Password : password
}
const authenticationDetails = new AuthenticationDetails(authenticationData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
console.log(result);
},
onFailure: (err) => {
console.log("Authenticate user failure");
console.log(err);
this.setState({ isInvalidForm: true });
},
newPasswordRequired: (userAttributes) => {
delete userAttributes.email_verified;
delete userAttributes.phone_number_verified;
userAttributes.name = authenticationDetails.username;
console.log(userAttributes);
this.setState({
isFirstLogin: true,
user: cognitoUser,
userAttr: userAttributes
});
}
});
}
updatePassword = (newPassword) => {
const cognitoUser = this.state.user;
const userAttr = this.state.userAttr;
cognitoUser.completeNewPasswordChallenge(newPassword, userAttr, {
onSuccess: (result) => {
console.log("NEW PASSWORD COMPLETED: ");
console.log(result);
},
onFailure: (err) => {
console.log(err);
}
});
}
render() {
return (
<div>
{this.state.isFirstLogin ? (
<NewPasswordForm updatePassword={this.updatePassword} />
) : (
<LoginScreenComponent isInvalidForm={this.state.isInvalidForm} onFormSubmission={this.onFormSubmission}/>
)}
</div>
);
}
}
I believe you need to call completeNewPasswordChallenge within the newPasswordRequired callback.
newPasswordRequired: (userAttributes, requiredAttributes) => {
delete userAttributes.email_verified
cognitoUser.completeNewPasswordChallenge(newPw, userAttributes, {
onSuccess: result => {
AWS.config.credentials.refresh(err => {
if (err) {
throw err
} else {
// do something
}
})
},
newPasswordRequired: (userAttributes, requiredAttributes) => {
delete userAttributes.email_verified
// phone number as well
cognitoUser.completeNewPasswordChallenge(newPw, userAttributes, this.newPasswordRequired)
},
onFailure: err => {
throw err
}
})
},
I believe you have MFA on your account and you need to handle it from callback:
mfaSetup: (challengeName, challengeParameters) => { ... }
When you're handling mfaSetup form cognitoUser.authenticateUser() callback all is good if it's required, but from completeNewPasswordChallenge() callback there is no mfaSetup() in typings, which I believe AWS colleagues should fix it ASAP.
That's why you have empty error code, please check response tab in network dev tools on post req you made. I believe you'll find there MFA_SETUP challenge to solve.

React Redux Firebase Keep user logged in function

I added my login and logout functions and its working properly, but I don't know how to keep users logged in? Any quick advices? Thanks. This is my login logout actions:
export function logout_action() {
return dispatch => {
firebase.auth().signOut()
.then(function () {
const logged_value = null;
dispatch(login({
...logged_value
}));
}).catch(function (error) {
// An error happened.
});
}
}
export function login_action() {
return dispatch => {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function (result) {
const logged_value = result.user;
dispatch(login({
...logged_value
}));
}).catch(function (error) {
var errorCode = error.code;
});
}
}
You can save the result either on the redux store or save it in window.localstorage when the user logins in and when they logout you can delete the result from window.localstorage or the redux store.

Resources