In a react-native application, dispatching an action that invokes firebase-auth to sign-out ends in a firebase permission error:
Here's the method inside the drawer component that dispatches the action:
logout = () => {
this.props
.logoutUser()
.then(() => {
this.props.navigation.navigate('Login');
})
.catch((err) => alert(err));
};
and here's the logout action:
export const logoutUser = () => {
return (dispatch) => {
return new Promise((resolve, reject) => {
firebase
.auth()
.signOut()
.then(() => {
dispatch({ type: types.RESET_APP });
console.log('Dispatching types.RESET_APP');
resolve();
})
.catch((error) => reject(error.message));
});
};
};
When executed, the screen reverts back to the login screen as desired. Console logs Dispatching types.RESET_APP, and THEN the error above displays.
authStateChanged Listener in my login:
export const loginUser = (email, password) => {
return (dispatch) => {
dispatch({ type: types.LOGIN_USER });
// listen for change in auth state before signing in
return new Promise((resolve, reject) => {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then((userCredential) => {
console.log('User Credential: ' + JSON.stringify(userCredential));
const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log('Logged in: ' + user.email);
loginUserSuccess(dispatch, user);
resolve(user);
} else {
console.log('Authentication state changed, user object is null...');
//resetAuth();
}
});
// No longer need to listen to auth state
unsubscribe();
})
.catch((error) => {
console.log('Error during Email sign-in: ' + error);
loginUserFail(dispatch, error.message);
});
});
};
};
auth state observer is unsubscribed in the login function, so whats causing this?
Related
I have login code in react native using firebase and google signin auth.
So when new user sign in using google account, I set new data. And if user has signed in before, user go to main page.
My problem is when new user sign in > code start to get signInWithCredential > set new data user, before set data finish, onAuthStateChanged was detect there is change in auth and start to get user document / data. But because it's not finish yet, it throw error 'Can Not Get UID / Undefined UID'.
This is my login page code:
const _signIn = async () => {
setInitializing(true);
try {
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
const credential = auth.GoogleAuthProvider.credential(
userInfo.idToken,
userInfo.accessToken,
);
await auth()
.signInWithCredential(credential)
.then(response => {
const uid = response.user.uid;
const data = {
uid: uid,
email: userInfo.user.email,
fullname: userInfo.user.name,
bio: 'Halo!! ..',
username: uid.substring(0, 8),
};
const usersRef = firestore().collection('users');
usersRef
.doc(uid)
.get()
.then(firestoreDocument => {
if (!firestoreDocument.exists) {
usersRef
.doc(data.uid)
.set(data)
.then(() => {
setInitializing(false); return;
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
return;
}
})
.catch(error => {
Alert.alert(JSON.stringify(error.message));
console.log('Error getting document:', error);
return;
});
});
} catch (error) {
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
setInitializing(false);
Alert.alert('Sign in canceled');
} else if (error.code === statusCodes.IN_PROGRESS) {
setInitializing(false);
Alert.alert('Signin in progress');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
setInitializing(false);
Alert.alert('PLAY_SERVICES_NOT_AVAILABLE');
} else {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
}
}};
And this is my index page code to check auth user:
useEffect(() => {
try {
NetInfo.fetch().then(state => {
if(state.isConnected === false){
Alert.alert('No Internet Connection Detected');
setInitializing(false);
return;
}
});
setInitializing(true);
await auth().onAuthStateChanged(user => {
if (user) {
const usersRef = firestore().collection('users');
usersRef
.doc(user.uid)
.get()
.then(document => {
const userData = document.data().uid;
setisLogin(userData);
})
.then(() => {
setInitializing(false);
})
.catch(error => {
setInitializing(false);
Alert.alert(JSON.stringify(error.message));
});
} else {
setInitializing(false);
}
});
} catch (error) {
Alert.alert(error);
} }, []);
How to wait auth().signInWithCredential finish? Thankyou.
If you need to perform more actions such read data from database or so after the user logs in, you should ideally unsubscribe from onAuthStateChanged. Essentially it won't trigger when the auth state changes (i.e. user logs in) and let you do your own custom actions. Once your processing is done, then you manually redirect the user to where the onAuthStateChange would have redirected is the user wa s logged in.
const authStateListenter = await auth().onAuthStateChanged(user => {
//...
})
// Unsubscribe auth state observer when _signIn function runs
const _signIn = async () => {
setInitializing(true);
authStateListenter()
}
Calling authStateListener will disable the auth state observer. It's similar to detaching Firestore's listeners.
I'm getting undefined ID after using createUserWithEmailAndPassword function.
Here is the code:
return async (dispatch) => {
dispatch({ type: ATTEMPTING });
if(name && email && password)
{
try {
await firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => handleAccountCreated(dispatch, user.uid, name,email,radio))
.catch(error => handleError(dispatch, error.message));
}catch(e) {
handleError(dispatch, e.message);
}
}else{
handleError(dispatch, "There is an error in your data");
}
}
const handleAccountCreated = (dispatch, userId, name,email , radio) => {
const ip = '223';
firebase.database().ref(`mydatabase/${userId}`)
.set({ name ,email,ip,radio})
.then(() => { dispatch({ type: SIGNUP_SUCCESS }); })
.catch(error => handleError(dispatch, error.message));
}
I have already tried with :
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(firebase.auth().onAuthStateChanged( user => handleAccountCreated(dispatch, user.uid, name, email ,radio)))
the same issue
I want to validate my login form in react native. but i used another Firebase logging function in onChangetext in react native.
This is my onPress function in the login button press.
async onLoginPress() {
this.setState({ errorMessage: null, loading: true });
const { email, password } = this.state;
console.log(email);
console.log(password);
firebase
.auth()
.signInWithEmailAndPassword(this.state.email, this.state.password)
.then(() => {
this.setState({ loading: false });
// this.props.navigation.navigate("Friendlist");
})
.catch(() => {
//var errorCode = error.code;
//var errorMessage = error.message;
this.setState({
error: 'AUTHENTICATION FAILED',
loading: false
});
});
await AsyncStorage.setItem("email", email);
await AsyncStorage.setItem("password", password);
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({
loading: false
});
}
});
}
and this is my onChangetext define in TextInput
onChangeText={email => this.setState({ email })}
I want to add validate functions with these functions. how caI i do that?
You can add multiple functions in the onChangeText callback as
onChangeText={async email => {
await method1()
await method2()
...
}}
but I would recommend you to use callback since you're using setState. This ensures the setState is updated before the callback in it is called
onChangeText={email => this.setState({ email }, () => this.validate(email))}
I am trying to login with phone number with firebase signInWithPhoneNumber() method for login. In which i have checked whether user auth state has been change or not. If user auth is change then login and redirect to home page. but i m getting auth null
onLoginBtnClicked() {
const { contact, password } = this.props;
const error = Validator('password', password) || Validator('contact', contact);
if (error !== null) {
Alert.alert(error);
} else {
console.log('else');
// this.props.loginUser({ contact, password});
const mobileNo = '+91'+contact;
firebase.auth().signInWithPhoneNumber(mobileNo)
.then(data => console.log(data),
firebase.auth().onAuthStateChanged((user) => {
console.log('user'+user);
if (user && !CurrentUser.isFirstTimeUser) {
const userRef = firebase.database().ref(`/users/`);
userRef.on("value", (snapshot) => {
console.log(snapshot.val());
snapshot.forEach(function(item) {
var itemVal = item.val();
if(itemVal.mobile == contact){
NavigationService.navigate('Home');
}
});
}, (errorObject) => {
console.log("The read failed: " + errorObject.code);
});
//NavigationService.navigate('Home');
}
})
)
.catch(error => console(error.message) );
}
}
There are two things to note here
onAuthStateChanged is a listener which listen for the user auth changes.
signInWithPhoneNumber sends the code to the user's phone, you have to confirm it to authenticate the user.
You need to add the listener in the react lifecycle for the component once it is mounted and remove it when it is unmounted
componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ user: user.toJSON() });
} else {
// Reset the state since the user has been logged out
}
});
}
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();
}
// Send Message here
firebase.auth().signInWithPhoneNumber(mobileNo)
.then(confirmResult => this.setState({ confirmResult })
.catch(error => // handle the error here)
// Authenticate User typed Code here
const { userCode, confirmResult } = this.state;
if (confirmResult && userCode.length > 0) {
confirmResult.confirm(codeInput)
.then((user) => {
// handle user confirmation here or in the listener
})
.catch(error => // handle the error here)
}
Before iOS 11.3 my app is working fine, but after the ios 11.3 was released new users from facebook cannot login to my app. But exisiting users still can login via facebook using their fb accounts.
im new too React native can please anyone help me. this is my facebook login code:
export const fbLogin = () => async dispatch => {
dispatch({ type: LOADING_TRUE });
LoginManager.logInWithReadPermissions([
'public_profile',
'user_birthday',
'email',
'user_photos'
]).then(
result => {
if (result.isCancelled) {
console.log('cancelled');
dispatch({ type: ERROR_HANDLER });
} else {
AccessToken.getCurrentAccessToken().then(data => {
const token = data.accessToken;
fetch(
'https://graph.facebook.com/v2.8/me?fields=id,name,email,gender,birthday&access_token=' +
token
)
.then(response => response.json())
.then(json => {
let userData = json;
let id = userData.id;
const fbProfilePic = `https://graph.facebook.com/${id}/picture?height=150`;
dispatch({
type: GET_PROFILE_PICTURE,
payload: fbProfilePic
});
const credential = firebase.auth.FacebookAuthProvider.credential(
token
);
firebase
.auth()
.signInWithCredential(credential)
.then(user => {
console.log('firebase facebook login!');
let currentUser = firebase.auth().currentUser;
if (currentUser !== null) {
const name = currentUser.displayName;
const email = currentUser.email;
const uid = currentUser.uid;
const birthday = json.birthday;
const gender =
json.gender === Languages.common.male_en
? Languages.common.male
: Languages.common.female;
userData.gender = gender;
let userDetails;
const db = firebase.firestore();
const docRef = db.collection('users').doc(uid);
docRef
.get()
.then(doc => {
if (doc.exists) {
// more than 2 times login
dispatch({
type: GET_USER_DATA,
payload: doc.data()
});
} else {
// first log in
const dateCreated = Moment()
.format('YYYY-MM-DD hh:mm:ss')
.toString();
userDetails = docRef.set({
name,
email,
birthday,
gender,
dateCreated,
uri: fbProfilePic
});
dispatch({
type: GET_USER_DATA,
payload: userData
});
}
})
.catch(error => {
dispatch({
type: ERROR_HANDLER,
payload: error
});
});
Actions.checkInHistory();
}
})
.catch(error => {
dispatch({
type: ERROR_HANDLER,
payload: `Error: ${error}`
});
});
})
.catch(err => {
dispatch({
type: ERROR_HANDLER,
payload: err
});
});
});
}
},
error => {
dispatch({
type: ERROR_HANDLER,
payload: error
});
}
);
};
Then this error is appearing:
this error is coming from my last error handler
I dont know what happened but when I put LoginManager.logOut() before the LoginManager.logInWithReadPermissions() new facebook users can now login to my app.