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

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.

Related

React-Native + Apple sign-in + Firestore: permission-denied

I'm trying to add Apple Sign-In to my project which is based on react native and firestore. Authentication flow itself works fine but firestore security rules reject my request when I try to create a user profile afterwards.
Firebase security rules:
rules_version = '2';
service cloud.firestore {
match /users/{userId} {
allow create:
if request.auth != null;
...
}
...
}
Simplified React Native code:
import { firebase } from './config';
import { firebase as RNFBAuth } from '#react-native-firebase/auth';
// Step 1
const credential = RNFBAuth.auth.AppleAuthProvider.credential(token, nonce);
// Step 2
RNFBAuth.auth().signInWithCredential(credential).then((response) => {
if (response.additionalUserInfo.isNewUser) {
// Step 3
firebase.firestore()
.collection('users')
.doc(uid)
.set({
// profile details
})
.then(() => {
// update local state
})
.catch((_error) => {
console.log(_error + ": " + _error.code);
});
}
});
Step 3 is failing with error code FirebaseError: The caller does not have permission: permission-denied.
Error is gone when Firestore security rules are downgraded to "allow create: if true". Unfortunately it does not fly for me for obvious reasons.
My guess is firebase/firestore does not know that user completed authentication via firebase/auth package thus request in "Step 3" is being send as unauthenticated one. Any ideas how to sync them?
Other Auth Providers like Google and Facebook are located at the main firebase package instead of firebase/auth thus same problem does not apply for them:
const credential = firebase.auth.FacebookAuthProvider.credential(token);
const credential = firebase.auth.GoogleAuthProvider.credential(token);
const credential = RNFBAuth.auth.AppleAuthProvider.credential(token, nonce);
Any ideas how to solve it?
Eventually the problem has been found - incompatible package versions. I've upgraded all firebase packages and #invertase/react-native-apple-authentication to the latest versions and everything seems to work fine now.
As sugested in the comment you should use the onAuthStateChanged listener:
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
var uid = user.uid;
// ...
} else {
// User is signed out
// ...
}
});
That way you have a general solution for all auth providers. It would not matter wich one you use. The trigger will be fired asap a user is signed in. I also use that method in all of my apps to sync user data.
You can read more about it here.

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 Google login not staying persistence

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...

Any way to use Firebase google authentication in expo (create-react-native-app) without "eject" project

As the question, for Login with google in firebase need to set google-service but if you create new react-native project with create-react-native-app there will have no "android" or "ios" folder (accept used "eject") so, anyone have a suggestion for me?
However I've no idea for how to setting google-service in my project too (even I "eject" the project).
#brentvatne 's answer is a bit out of date. Here's how I got it working on Expo v27
Important bit: you can get your client ids with these instructions.
Just select your firebase app from the project dropdown on the google page.
const _loginWithGoogle = async function() {
try {
const result = await Expo.Google.logInAsync({
androidClientId:"YOUR_ANDROID_CLIENT_ID",
iosClientId:"YOUR_iOS_CLIENT_ID",
scopes: ["profile", "email"]
});
if (result.type === "success") {
const { idToken, accessToken } = result;
const credential = firebase.auth.GoogleAuthProvider.credential(idToken, accessToken);
firebase
.auth()
.signInAndRetrieveDataWithCredential(credential)
.then(res => {
// user res, create your user, do whatever you want
})
.catch(error => {
console.log("firebase cred err:", error);
});
} else {
return { cancelled: true };
}
} catch (err) {
console.log("err:", err);
}
};
It isn't necessary to make any changes to the android or ios folders in order to support Google sign in with firebase on an app built with Expo.
Follow the guide for configuring Google auth on the Expo docs
Use the approach described in Expo's Using Firebase guide, where it describes how to authenticate with Facebook, and swap out Google where needed.

How to add additional information to firebase.auth()

How can I add extra attributes phone number and address to this data set? It seems like Firebase documentation doesn't specify anything about that.
I have implemented the login, register and update using firebase.auth()
Login :
//Email Login
firebase.auth().signInWithEmailAndPassword(email, password).then(
ok => {
console.log("Logged in User",ok.user);
},
error => {
console.log("email/pass sign in error", error);
}
);
Register:
//Sign Up
firebase.auth().createUserWithEmailAndPassword(email, password).then(
ok => {
console.log("Register OK", ok);
},
error => {
console.log("Register error", error);
}
)
Update:
//User Authentication
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
$scope.data=user;
} else {
// No user, Redirect to login page
}
});
//Save Function
$scope.save=function(values){
$scope.data.updateProfile({
displayName: "Test User",
email: "test#gmail.com",
/* phone: 123412341,
address: "Temp Address",*/
photoURL: "www.example.com/profile/img.jpg"
}).then(function() {
// Update successful.
}, function(error) {
// An error happened.
});
};
As far as I know, you have to manage the users profiles by yourself if you want to have more fields than the default user provided by Firebase.
You can do this creating a reference in Firebase to keep all the users profiles.
users: {
"userID1": {
"name":"user 1",
"gender": "male"
},
"userID2": {
"name":"user 2",
"gender": "female"
}
}
You can use onAuthStateChanged to detect when the user is logged in, and if it is you can use once() to retrieve user's data
firebaseRef.child('users').child(user.uid).once('value', callback)
Hope it helps
This can be done by directly storing your custom data in Firebase Auth as "custom claims" on each user via the Admin SDK on your backend.
Note this can't be done purely client-side, your server (or you can use a Cloud Function as per the linked guide if you don't already have a server/API set up) needs to make a request through the Admin SDK to securely set the data using the admin.auth().setCustomUserClaims() method:
https://firebase.google.com/docs/auth/admin/custom-claims#defining_roles_via_an_http_request
You could write some code that combines data from firebase auth and firestore document and expose that to the app as a single data entity. To take subscriptions and notify that changes to the whole app, you would be better served with event libraries like Rxjs. Bellow, I wrote the example below using a simple library that implements an event bus.
// auth.js
import { publish } from '#joaomelo/bus'
import { fireauth, firestore } from './init-firebase.js'
const authState = {
userData: null
};
fireauth.onAuthStateChanged(user => {
if (!user) {
authState.userData = null;
publish('AUTH_STATE_CHANGED', { ...authState });
return;
}
// we must be carefull
// maybe this doc does not exists yet
const docRef = firestore
.collection('profiles')
.doc(user.uid);
docRef
// 'set' secures doc creation without
// affecting any preexisting data
.set({}, { merge: true })
.then(() => {
docRef.onSnapshot(doc => {
// the first data load
// and subsequent updates
// will trigger this
authState.userData = {
id: user.uid,
email: user.email,
...doc.data()
};
publish('AUTH_STATE_CHANGED', { ...authState });
});
});
});
// some-place-else.js
import { subscribe } from '#joaomelo/bus'
subscribe('AUTH_STATE_CHANGED',
authState => console.log(authState));
You can expand on that in a post I wrote detailing this solution and also talking about how to update those properties. There is too a small library that encapsulates the answer with some other minor features with code you could check.

Resources