firestore is not synced with user authentication, keep returning all data for all the users. The firestore rules I have been writing are this but it keeps on returning errors
https://i.stack.imgur.com/AFv5r.png
This useEffect is used to return data when the user signs in but
https://i.stack.imgur.com/PDP2Z.png
it keeps giving error
https://i.stack.imgur.com/X5Hv0.png
Related
My application is a company-internal software. I want to enable all authenticated users to access all documents in the Firestore for tests.
I ran into a mistake while doing this.
The user logs in to the iOS app and has access to the documents.
I delete the user from Firebase Auth (via Firebase console)
As long as the user has the app open, he receives updates and can read and write.
Here is the code from the rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read : if request.auth != null
allow write: if request.auth != null
}
}
}
How can I prevent deleted users from continuing to have access?
The user logs in to the iOS app and has access to the documents.
That's the expected behavior.
I delete the user from Firebase Auth (via the console) As long as the user has the app open, he receives updates and can read and write.
When a user signs in with Firebase, he receives a token that is valid for about an hour. Unfortunately, such a token cannot be revoked, due to expensive checks on each call.
If you delete a user account right from the Firebase Console, the user can still have access for up to an hour. After that period of time, the token needs to be refreshed. But this operation will fail since that account doesn't exist anymore. So that access will automatically be disabled within an hour.
However, if you want to remove that access before the token expires, then you should consider keeping an additional list of banned UIDs and maintaining it over time. For instance, you can keep a global list/array of bannedUIDs into a document, and add the UID to that. Lastly, in your security rules, you can check if that particular UID is not banned. If that UID exists inside that list, then Firebase servers will reject the operation.
Edit:
Another option might be to disable the user account. This accomplishes the same as above and the user won't be able to get a new token after the current token expires. It also prevents the user from signing up again with the same credentials.
Firestore.firestore().document("someCol/someDoc").updateData([
"someField": FieldValue.delete()
]) { (error) in
// returns nothing in the scenario described below
}
The client is signed into Firebase Auth.
The Firestore security rules require authentication to perform writes.
The client is offline and performs a write operation.
If the client signs out of Auth before it comes back online, the write will not execute, as I would expect. I assume this is because the authentication credentials were not queued with the write operation when the client was offline. Can this be confirmed? However, I would expect the completion handler of this write operation to return an error, but it returns nothing. Why does it return nothing and is this the way it should behave?
In a normal situation the Authentication SDK will try to refresh the auth credentials once the connection is restored, before it tries to commit the writes to Firestore.
If you explicitly sign the user out while offline, that refresh won't happen as you signed the user out, so your writes will indeed fail.
I'm not sure why you don't get an error in your completion handler, but it's hard to be certain of anything without seeing the exact flow of all three components: Firestore writes, user authentication state, and being online/offline. A repro in a site like jsbin/stackblitz might be the easiest way to share that in a minimal form.
Am calling these functions in sequence (javascript 'firebase`):
firebase
.auth()
.signInWithEmailLink(email, url)
.then(userCred => {
return firebase.firestore().collection('users').doc('someDocID').get()
....
I have security rules setup in firestore that allows read of 'users/:docId' only if the email field in that document equals the auth email:
allow get: if request.auth.token.email == resource.data.email
The problem is we get a missing or insufficient permissions error on the get().
For sure the email in the database is correct so the only problem could be is that request.auth.token.email is not valid.
Could it be that signing in (using any sign in function), even if resolves, doesn't guarantee the auth token is updated and can be immediately used ?
Is there propagation time? should we call getIdToken() after sign in resolves to make sure the token is valid before making database/firestore calls?
When a user actively signs in (by calling any of the signInWith... methods), the client gets an ID token, which contains the up-to-date values for that user. That ID token is valid for an hour, and is then auto-refreshed by the client/SDK.
So right after the signIn... call, the profile should contain the latest values. If you think something is going wrong there, I'd recommend logging the values right before making the call to Firestore.
I have a RTDB in firebase in which I have a users subset. I currently have it configured to authorized users can make read requests, which I am fine with. However, I need to make a read request on a subset in my database (username in my users) allowed always, and another subset not reading but saying true or false based on whether a given email is in the users object (allow read but only for comparisons?). I am not sure if this is possible in firebase.
I am sending REST requests to the service as: "myfirebaselink/users.json?only="username", but this does not work.
My database structure:
users ...
{uid} ...
email
username
I am using Firebase Web for a SaaS solution. My purpose is to have access to users' email at any time, either for sending notifications or triggering alerts from the backend.
For security reasons, Firebase auth does not allow to list users' email or to fetch emails based on user IDs. As a consequence, I keep a copy of the email into a specific collection in the Firebase database when a user account is created. The copy is made by a Cloud function that is triggered on user creation (following guidelines: https://firebase.google.com/docs/auth/extend-with-functions).
Thanks to the copy available in the Firebase database, I can access users' email. However, my issue is when a user changes his email.
Firebase auth provides the updateEmail function that returns a promise. I use this last to update the email in Firebase auth. Then, when the promise resolves I update the user email in the Firebase database. However, this has a major drawback: all the logic is performed on the client side and since both operations are not performed in a transaction if the client refreshes or closes his browser (or assume it crashes), then it is possible that Firebase auth is updated but not the Firebase database, thus leading to an inconsistent state.
I looked at the documentation, expecting the possibility to trigger a Cloud function when user auth information is updated. Unfortunately, I cannot find such a feature.
Another solution I thought about is to update the database from the Web client. Then, this last triggers a Cloud function that updates Firebase auth with the admin SDK. This last solution works but bypasses the check performed by updateEmail that ensures the new email is not used by another account. Also, the account hijacking protection performed by updateEmail is evicted, which is really bad from a security point of view.
Any idea to solve this problem properly is welcome.
Here are a couple of options:
When calling updateEmail, update the email in your database first before calling updateEmail. THowever, if an error occurs, you need to catch it and undo that change in your db.
When a user wants to updateEmail, send their id token and new email to your server or firebase function http endpoint. There you verify the ID token with the admin SDK, then use the client SDK require('firebase'), using the uid from the ID token, admin.auth().createCustomToken(uid), then using client SDK, firebase.auth().signInWithCustomToken(customToken). You can then call user.updateEmail(newEmail) on the backend and save the email.
Always save the uid only and just use Admin SDK admin.auth().getUser(uid) to look up the user and get their email. This guarantees you get the user's latest email as you will not be able to catch the email revocation if the user chooses to do so.
No need to save anything. Use the CLI SDK to download all your users and their emails. Check https://firebase.google.com/docs/cli/auth#authexport
This is also better as you will always be able to get the latest email per user even if they revoke the email change.