Firebase Google login not staying persistence - firebase

I am developing an application, with an feature of Google Login through Firebase. I am trying to login via Google with the help of an library, known as react-native-google-signin. It is well known library in the field of ReactNative for Google Login.
My problem is not with this library, but the problem is that while I am using react-native-google-signin library with firebase to login via google. Firebase User is not staying persistence, I mean to say that when I am opening app after close FirebaseUser is getting null. Below the code I am using to login via firebase,
GoogleSignin.signIn().then(data => {
const credentials = firebase.auth.GoogleAuthProvider.credential(data.idToken, data.accessToken);
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL)
.then() => {
return firebase.auth().signInWithCredential(credentials);
}).catch(error => {
console.log('Error', error);
})
}).then(user => {
console.log('user', firebase.auth().currentUser);
}).catch(error => {
console.log('Error', error);
})
I also checked Firebase Docs, tried by using setPersistence() method but still I am getting null user after open app again.

You can try this
when you first time open your app you get user null, but after login one time then reopen your app and you will get previously logged in user in your console
async _setupGoogleSignin() {
try {
await GoogleSignin.hasPlayServices({ autoResolve: true });
await GoogleSignin.configure({
webClientId: 'YOUR WEBCLIENTID',
offlineAccess: false
});
const user = await GoogleSignin.currentUserAsync();
console.log("user",user); // HERE YOU GET LOGGED IN USER IN YOUR CONSOLE FIRST TIME IT WILL BE NULL BUT AFTER YOU GET PREVIOUSLY LOGGED IN USER
this.setState({user});
}
catch(err) {
console.log("Play services error", err.code, err.message);
}}
then
_signIn() {
GoogleSignin.signIn()
.then((user) => {
console.log(user);
this.setState({user: user});
const credential = firebase.auth.GoogleAuthProvider.credential(user.idToken, user.accessToken);
// console.log(credential);
return firebase.auth().signInAndRetrieveDataWithCredential(credential);
})
.catch((err) => {
console.log('WRONG SIGNIN', err);
})
.done();}
it is worked for me...
hope it will help you...

Related

React Native, Firebase: Error (auth/admin-restricted-operation) fix?

const handleSignUp = () => {
createUserWithEmailAndPassword(auth, email, password)
.then((re) => {
console.log(re);
})
.catch((error) => {
console.log(error);
}
);
};
This is the signup function that I've implemented for email and password authentication using Firebase authentication. The error that I'm getting is,
Firebase: Error (auth/admin-restricted-operation).
This happens every time I run this function and the firebase authentication tab does not show the new user. Been stuck on this error for quite a while now and am unable to fix it. Any help would be highly appreciated.

firebase DB initialized multiple times. Make sure the format of the database URL matches with each db call

I am getting this error while loading the firebase database.
I have deleted the data while I am fixing another issue, Expo Go stopping. my firebase database expires in a day, I have changed the rules to make it work
{
"rules": {
"users": {
".read": true,
".write": false
}
}
}
const onSignIn =(googleUser) => {
console.log('Google Auth Response', googleUser);
// We need to register an Observer on Firebase Auth to make sure auth is initialized.
const unsubscribe = firebase
.auth()
.onAuthStateChanged((firebaseUser) => {
unsubscribe();
// Check if we are already signed-in Firebase with the correct user.
if (!isUserEqual(googleUser, firebaseUser)) {
// Build Firebase credential with the Google ID token.
const credential = firebase.auth.GoogleAuthProvider.credential(
googleUser.idToken,
googleUser.accessToken,
);
console.log('I am here lately!');
// Sign in with credential from the Google user.
//In debugging my code the next auth line is breaking the execution
firebase.auth().signInWithCredential(credential).then((result) => {
console.log("user signed in !!")
if (result.additionalUserInfo.isNewUser) {
firebase
.database()
.ref('/users/' + result.user.uid)
.set({
gmail: result.user.email,
profile_picture: result.additionalUserInfo.profile.picture,
first_name: result.additionalUserInfo.profile.given_name,
last_name: result.additionalUserInfo.profile.family_name,
created_at: Date.now(),
}).then(response => console.log("user info set!"));} else { firebase.database()
.ref('/users/' + result.user.uid)
.update({
`enter code here`last_logged_in: Date.now()
})
}
})
.catch((error) => {
console.log("Error in Signinig into firebase", error)});
} else {
console.log('User already signed-in Firebase.');
} })
}
Can anyone help me out to make my firebase database work normally? I got stuck here and unable to develop further after logging in screens in my app.
The following is the issue for me, but I have changed the rules set within 24 hours, will it be effective after 24 hours??
24 hours after changing the rules is completed but my issue is not solved. the app is crashing suddenly while login. Please help me out.

How to use Firebase's 'verifyPhoneNumber()' to confirm phone # ownership without using # to sign-in?

Im using react-native-firebase v5.6 in a project.
Goal: In the registration flow, I have the user input their phone number, I then send a OTP to said phone number. I want to be able to compare the code entered by the user with the code sent from Firebase, to be able to grant entry to the next steps in registration.
Problem: the user gets the SMS OTP and everything , but the phoneAuthSnapshot object returned by firebase.auth().verifyPhoneNumber(number).on('state_changed', (phoneAuthSnapshot => {}), it doesn't give a value for the code that firebase sent, so there's nothing to compare the users entered code with. However, there's a value for the verificationId property. Here's the object return from the above method:
'Verification code sent', {
verificationId: 'AM5PThBmFvPRB6x_tySDSCBG-6tezCCm0Niwm2ohmtmYktNJALCkj11vpwyou3QGTg_lT4lkKme8UvMGhtDO5rfMM7U9SNq7duQ41T8TeJupuEkxWOelgUiKf_iGSjnodFv9Jee8gvHc50XeAJ3z7wj0_BRSg_gwlN6sumL1rXJQ6AdZwzvGetebXhZMb2gGVQ9J7_JZykCwREEPB-vC0lQcUVdSMBjtig',
code: null,
error: null,
state: 'sent'
}
Here is my on-screen implementation:
firebase
.firestore()
.collection('users')
.where('phoneNumber', '==', this.state.phoneNumber)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty === true) {
// change status
this.setState({ status: 'Sending confirmation code...' });
// send confirmation OTP
firebase.auth().verifyPhoneNumber(this.state.phoneNumber).on(
'state_changed',
(phoneAuthSnapshot) => {
switch (phoneAuthSnapshot.state) {
case firebase.auth.PhoneAuthState.CODE_SENT:
console.log('Verification code sent', phoneAuthSnapshot);
this.setState({ status: 'Confirmation code sent.', confirmationCode: phoneAuthSnapshot.code });
break;
case firebase.auth.PhoneAuthState.ERROR:
console.log('Verification error: ' + JSON.stringify(phoneAuthSnapshot));
this.setState({ status: 'Error sending code.', processing: false });
break;
}
},
(error) => {
console.log('Error verifying phone number: ' + error);
}
);
}
})
.catch((error) => {
// there was an error
console.log('Error during firebase operation: ' + JSON.stringify(error));
});
How do I get the code sent from Firebase to be able to compare?
As #christos-lytras had in their answer, the verification code is not exposed to your application.
This is done for security reasons as providing the code used for the out of band authentication to the device itself would allow a knowledgeable user to just take the code out of memory and authenticate as if they had access to that phone number.
The general flow of operations is:
Get the phone number to be verified
Use that number with verifyPhoneNumber() and cache the verification ID it returns
Prompt the user to input the code (or automatically retrieve it)
Bundle the ID and the user's input together as a credential using firebase.auth.PhoneAuthProvider.credential(id, code)
Attempt to sign in with that credential using
firebase.auth().signInWithCredential(credential)
In your source code, you also use the on(event, observer, errorCb, successCb) listener of the verifyPhoneNumber(phoneNumber) method. However this method also supports listening to results using Promises, which allows you to chain to your Firebase query. This is shown below.
Sending the verification code:
firebase
.firestore()
.collection('users')
.where('phoneNumber', '==', this.state.phoneNumber)
.get()
.then((querySnapshot) => {
if (!querySnapshot.empty) {
// User found with this phone number.
throw new Error('already-exists');
}
// change status
this.setState({ status: 'Sending confirmation code...' });
// send confirmation OTP
return firebase.auth().verifyPhoneNumber(this.state.phoneNumber)
})
.then((phoneAuthSnapshot) => {
// verification sent
this.setState({
status: 'Confirmation code sent.',
verificationId: phoneAuthSnapshot.verificationId,
showCodeInput: true // shows input field such as react-native-confirmation-code-field
});
})
.catch((error) => {
// there was an error
let newStatus;
if (error.message === 'already-exists') {
newStatus = 'Sorry, this phone number is already in use.';
} else {
// Other internal error
// see https://firebase.google.com/docs/reference/js/firebase.firestore.html#firestore-error-code
// see https://firebase.google.com/docs/reference/js/firebase.auth.PhoneAuthProvider#verify-phone-number
// probably 'unavailable' or 'deadline-exceeded' for loss of connection while querying users
newStatus = 'Failed to send verification code.';
console.log('Unexpected error during firebase operation: ' + JSON.stringify(error));
}
this.setState({
status: newStatus,
processing: false
});
});
Handling a user-sourced verification code:
codeInputSubmitted(code) {
const { verificationId } = this.state;
const credential = firebase.auth.PhoneAuthProvider.credential(
verificationId,
code
);
// To verify phone number without interfering with the existing user
// who is signed in, we offload the verification to a worker app.
let fbWorkerApp = firebase.apps.find(app => app.name === 'auth-worker')
|| firebase.initializeApp(firebase.app().options, 'auth-worker');
fbWorkerAuth = fbWorkerApp.auth();
fbWorkerAuth.setPersistence(firebase.auth.Auth.Persistence.NONE); // disables caching of account credentials
fbWorkerAuth.signInWithCredential(credential)
.then((userCredential) => {
// userCredential.additionalUserInfo.isNewUser may be present
// userCredential.credential can be used to link to an existing user account
// successful
this.setState({
status: 'Phone number verified!',
verificationId: null,
showCodeInput: false,
user: userCredential.user;
});
return fbWorkerAuth.signOut().catch(err => console.error('Ignored sign out error: ', err);
})
.catch((err) => {
// failed
let userErrorMessage;
if (error.code === 'auth/invalid-verification-code') {
userErrorMessage = 'Sorry, that code was incorrect.'
} else if (error.code === 'auth/user-disabled') {
userErrorMessage = 'Sorry, this phone number has been blocked.';
} else {
// other internal error
// see https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#sign-inwith-credential
userErrorMessage = 'Sorry, we couldn\'t verify that phone number at the moment. '
+ 'Please try again later. '
+ '\n\nIf the issue persists, please contact support.'
}
this.setState({
codeInputErrorMessage: userErrorMessage
});
})
}
API References:
verifyPhoneNumber() - React Native or Firebase
PhoneAuthProvider.credential(id, code) - Firebase
signInWithCredential() - React Native or Firebase
Suggested code input component:
react-native-confirmation-code-field
Firebase firebase.auth.PhoneAuthProvider won't give you the code for to compare, you'll have to use verificationId to verify the verificationCode that the user enters. There is a basic example in firebase documentation than uses firebase.auth.PhoneAuthProvider.credential and then tries to sign in using these credentials with firebase.auth().signInWithCredential(phoneCredential):
firebase
.firestore()
.collection('users')
.where('phoneNumber', '==', this.state.phoneNumber)
.get()
.then((querySnapshot) => {
if (querySnapshot.empty === true) {
// change status
this.setState({ status: 'Sending confirmation code...' });
// send confirmation OTP
firebase.auth().verifyPhoneNumber(this.state.phoneNumber).on(
'state_changed',
(phoneAuthSnapshot) => {
switch (phoneAuthSnapshot.state) {
case firebase.auth.PhoneAuthState.CODE_SENT:
console.log('Verification code sent', phoneAuthSnapshot);
// this.setState({ status: 'Confirmation code sent.', confirmationCode: phoneAuthSnapshot.code });
// Prompt the user the enter the verification code they get and save it to state
const userVerificationCodeInput = this.state.userVerificationCode;
const phoneCredentials = firebase.auth.PhoneAuthProvider.credential(
phoneAuthSnapshot.verificationId,
userVerificationCodeInput
);
// Try to sign in with the phone credentials
firebase.auth().signInWithCredential(phoneCredentials)
.then(userCredentials => {
// Sign in successfull
// Use userCredentials.user and userCredentials.additionalUserInfo
})
.catch(error => {
// Check error code to see the reason
// Expect something like:
// auth/invalid-verification-code
// auth/invalid-verification-id
});
break;
case firebase.auth.PhoneAuthState.ERROR:
console.log('Verification error: ' + JSON.stringify(phoneAuthSnapshot));
this.setState({ status: 'Error sending code.', processing: false });
break;
}
},
(error) => {
console.log('Error verifying phone number: ' + error);
}
);
}
})
.catch((error) => {
// there was an error
console.log('Error during firebase operation: ' + JSON.stringify(error));
});
In order to use Multi-factor Authentication, you must create Phone Sign-in provider in the background alongside primary (in your case) email sign-in provider either initially or later while user choose to update settings and enables MFA. And then link it while user is logged using email sign-in provider as follows;
const credential = auth.PhoneAuthProvider.credential(verificationId, code);
let userData = await auth().currentUser.linkWithCredential(credential);
This is not supported by firebase unfortunately. Logging in and out after signInWithCredential can work, but is very confusing
I was facing the same difficulty. My aim was only to verify users' phone numbersenter image description here and then register them using email and password. After a long intense trial and error methodology, I have arrived at the solution. But the point is I am using firebase in my android application. what it did was
I first tried matching the OTP with the user entered OTP, but the OTP that firebase provides us in the backend is encrypted with some logic and the logic is nowhere in the documentation so I could not decrypt it.
The second approach worked for me. What I did was, I signed in the user using the phone authorization and when the task was successful I deleted the newly created user there itself and then signed in the user using email id and password.

signInWithEmailAndPassword: getting auth/user-token-expired [duplicate]

I am using Firebase authentication in my iOS app. Is there any way in Firebase when user login my app with Firebase then logout that user all other devices(sessions)? Can I do that with Firebase admin SDK?
When i had this issue i resolved it with cloud functions
Please visit this link for more details https://firebase.google.com/docs/auth/admin/manage-sessions#revoke_refresh_tokens
Do the following;
Set up web server with firebase cloud functions (if none exists)
use the admin sdk(thats the only way this method would work) - [Visit this link] (
(https://firebase.google.com/docs/admin/setup#initialize_the_sdk).
Create an api that receives the uid and revokes current sessions as specified in the first link above
admin.auth().revokeRefreshTokens(uid)
.then(() => {
return admin.auth().getUser(uid);
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
})
.then((timestamp) => {
//return valid response to ios app to continue the user's login process
});
Voila users logged out. I hope this gives insight into resolving the issue
Firebase doesn't provide such feature. You need to manage it yourself.
Here is the Firebase Doc and they haven't mentioned anything related to single user sign in.
Here is what you can do for this-
Take one token in User node (Where you save user's other data) in Firebase database and regenerate it every time you logged in into application, Match this token with already logged in user's token (Which is saved locally) in appDidBecomeActive and appDidFinishLaunching or possibly each time you perform any operation with Firebase or may be in some fixed time interval. If tokens are different logged out the user manually and take user to authenticate screen.
What i have done is:
Created collection in firestore called "activeSessions".User email as an id for object and "activeID" field for holding most recent session id.
in sign in page code:
Generating id for a user session every time user is logging in.
Add this id to localstorage(should be cleaned everytime before adding).
Replace "activeID" by generated id in collection "activeSessions" with current user email.
function addToActiveSession() {
var sesID = gen();
var db = firebase.firestore();
localStorage.setItem('userID', sesID);
db.collection("activeSessions").doc(firebase.auth().currentUser.email).set({
activeID: sesID
}).catch(function (error) {
console.error("Error writing document: ", error);
});
}
function gen() {
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
return buf[0];
}
function signin(){
firebase.auth().signInWithEmailAndPassword(email, password).then(function (user) {
localStorage.clear();
addToActiveSession();
}
}), function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
alert('wrong pass');
} else {
alert(errorMessage);
}
console.log(error);
};
}
Then i am checking on each page if the id session in local storage is the same as "activeID" in firestore,if not then log out.
function checkSession(){
var db = firebase.firestore();
var docRef = db.collection("activeSessions").doc(firebase.auth().currentUser.email);
docRef.get().then(function (doc) {
alert(doc.data().activeID);
alert(localStorage.getItem('userID'));
if (doc.data().activeID != localStorage.getItem('userID')) {
alert("bie bie");
firebase.auth().signOut().then(() => {
window.location.href = "signin.html";
}).catch((error) => {
// An error happened.
});
window.location.href = "accountone.html";
} else{alert("vse ok");}
}).catch(function (error) {
console.log("Error getting document:", error);
});
}
PS: window has to be refreshed to log inactive session out.

Firebase web auth via Google SSO - How to know whether a user registered or logged in

I want to detect whether the user has just registered via SSO or simply logged in.
The documentation wasn't helpful.
I'm using React + ES6. Here's my current auth method:
authWithGoogle = () => {
this.props.setIsLoggingInState(true);
firebaseApp
.auth()
.getRedirectResult()
.catch(() => console.error('something went wrong with Google SSO'));
firebaseApp
.auth()
.signInWithRedirect(googleProvider)
.catch(() => console.error('something went wrong with Google SSO'));
};
To be honest, the code above doesn't seem right... (but it works)
You can do the following:
firebaseApp.auth().getRedirectResult().then(function(userCredential) {
// True if the user is new, false if existing.
console.log(userCredential.additionalUserInfo.isNewUser);
}).catch(function(error) {
// Error occurred.
});

Resources