It is possible to erase a customer with InstanceID to comply with GDPR: https://godoc.org/firebase.google.com/go/iid#Client.DeleteInstanceID
However we do not have historical Firebase Instance IDs. BigQuery has a field app_info.app_instance_id but this is not a valid instance ID.
Is it possible to erase a customer with app_instance_id?
An app instance ID identifies (as its name implies) an app instance. It does not identify a specific user. While it is quite common to associate IIDs with users, Firebase has nothing built in for that. This means that, unless you have the data in your database, there is no way to find out the associated IIDs for a user by calling the API.
Related
My team is using Firebase Auth in our project. We're using custom claims to properly authenticate whether or not a user has access to a specific piece of information. We're storing each piece of information and deciding access for the user based off whether or not the user has access to a specific location. Each piece of data is somehow associated with a location, and we are storing the location id in the custom claims for the ID Token.
The problem is that a user potentially has access to thousands of locations. Instead of storing thousands of locations in the custom claims, we think it's better to generate a new custom token and exchange it for a fresh id token every time the user switches locations. That means that it's potentially reasonable for a user to generate a new custom token every few seconds as they switch through their locations if they are doing it quickly enough.
The Firebase Auth documentation doesn't indicate anything in regards to any rate limiting in this regard.
Are we going to run into any issues / rate limiting if a user switches through their locations very quickly? This would be unusual, but I just want to make sure that the worst case will still work.
The control of Firebase Authentication custom claims is an Admin SDK operation and as such is not subject to rate-limiting. Firebase Authentication as a whole is designed to handle millions of concurrent users and is subject to various rate limits. Updating a user's custom claims would only contribute to the overall limits of 1000ops/sec and 10 million ops/day (at time of writing).
However, custom claims should be used for access control related data that will infrequently change such as the name of a role or a building ID. This is because the propagation of changed custom claims can take up to an hour and requires that the client code manually refresh their tokens after any changes to see an immediate effect. Custom claims have no mechanism to notify clients that they have been updated.
I'd reconsider your approach and store the list of locations a particular user has access to in the Realtime Database or Cloud Firestore rather than the ID token itself. You can then use this information to secure their access using appropriate Security Rules for those databases based on their user ID. By configuring a listener to that portion of the database, your client code can be instantly notified when a user gains or loses access to a new location. Additionally, you can poll information from multiple locations at once so you can show information in a notification feed or dashboard - something that can't be done with the claims strategy.
I'm currently trying to figure out sign-up for my app. Right now, at sign up I ask users for a username alongside an email and password (for firebase_auth).
The thing is, I don't want more than one user with a username, so I need to check my database if there already exists a user with that username before signing up the user with firebase_auth and adding this new user to my database.
I'm concerned about a race condition that could arise if two users try to create an account with the same username at the same time. I'm trying to use TransactionHandler, but im not sure exactly how I can do this as I hear that a transaction might be run up to 5 times, and we shouldn't do anything that should not be run multiple times (i.e. sign up with firebase_auth?).
Any ideas as to how I can work around this?
There is no way to create a user account and create a document in the database atomically. So you'll have to instead find a way to deal with it in your application code.
Typically this comes from thinking of account creation as a sequence of steps. For example, this is quite common:
Create account in Firebase Authentication, based on the credentials the user enters.
Have the user verify their email address, so that you can reach them.
Have the user claim their unique user name.
You'll see that none of these steps depends on a step that comes after it, so you can execute them in order. And when you do that, step 3 should work fine in a transaction that may run multiple ties.
Just keep in mind: if you want something to be unique on Firestore, you need to use that value as the IDs of your documents. There is no way with client-side access (not even with transactions) to guarantee uniqueness of values across documents. For some more questions on that topic, see:
Firestore unique index or unique constraint?
Cloud Firestore: Enforcing Unique User Names
firebase rule for unique property in firestore, which uses a single document to store all user names.
Prevent duplicate entries in Firestore rules not working
Firebase is great as it offers a lot of authentication providers. In one of my apps, I use four different providers provided by Firebase (Email, Twitter, Facebook and Google), but I also need to let users sign in via LinkedIn.
As Firebase SDK does not offer LinkedIn, I need to implement the login flow manually, which doesn't seem to be difficult, but there is one huge issue which I see. During the creation of a custom JWT token, I need to assign a user ID. And I have no idea how to generate one while making sure that my approach will not conflict with user IDs which Firebase generate on its own for other providers.
For example, let's imagine that a user Andriy Gordiychuk signs in via LinkedIn and his email address is andriy#gordiychuk.com. A simple way to create a user ID would be to take an email address (andriy#gordiychuk.com) and to randomise it using some hashing function. I would get some random id such as aN59nlphs... which I would be able to recreate as long as the same user signs in. So far, so good.
However, how can I be sure that the ID which I get is not already used by another user who signed in via Twitter, for example?
One way to mitigate this issue is to store LinkedIn user IDs in a Firestore collection. Then, when I need to create a token, I first check whether I already have an ID for this user. If not, I would hash the email address, and I would try to create a user with this ID. If this ID is already occupied, I would then try to create another ID until I stumble upon an ID which is not occupied, and I would then use it.
I don't like this approach for two reasons:
Although the chance that I would generate an already occupied ID
is small, theoretically the process of finding an "available ID" can
take a lot of steps (an infinite loop in a worst-case scenario).
Once I find an available ID, I must store it. Given that all these calls are asynchronous there is a real chance that I would create a user with a suitable ID, but because the save operation fails, I would not be able to use this ID.
So, does anyone know how to choose user IDs for such use case correctly?
It's fairly common to generate a string with enough entropy (randomness) to statistically guarantee it will never be duplicated. This is for example behind the UUID generators that exist in many platforms, and similarly behind Firebase Realtime Database's push keys, and Cloud Firestore's add() keys. If there's one in your platform, I recommend starting with that.
Also see:
The 2^120 Ways to Ensure Unique Identifiers, which explains how Firebase Realtime Database's push() works.
Universally unique identifier, Version 4 on Wikipedia
the uuid npm module
I have a user-profile collection. Currently it is writable by only the user whose profile it is.
Now I want to record the count 'no of times the profile visited' let say profileVisitedCount. And, it also counts if a non-signedIn user visit the profile.
If I store the count in the documents of user-profile collection itself from firebase js client library, I will have to make it publicly writable.
Other option I am thinking is to have a cloud function. It will only increment the profileVisitedCount without need of making the the document publicly writable. But not sure if it is a correct approach, as the cloud function endpoint seems still vulnerable and can be called by bot.
Also, yes 'the profile visit count' kind of data should be recorded in analytics like GA but I need this count to use in one of the business logic like displaying top visited profiles.
So, any guidance on how the data should be structured? Thanks!
You could have another collection called, for example, profileVisitsCounters in which you store one document per user with a document Id corresponding to the user Id. In this user document, you maintain a dedicated profileVisitedCount field that you update with increment() each time a user reads the corresponding profile.
You assign full read and write access to this collection with allow read, write: if true;.
In your question, while mentioning the Cloud Function solution, you write that "the cloud function endpoint seems still vulnerable and can be called by bot". Be aware that in the case of an extra collection with full write access, as detailed above, it will also be the case: for example, someone who knows the collection name and user uid(s) could call the update() method of the JavaScript SDK or, even easier, an endpoint of the Cloud Firestore API.
If you want to avoid this risk you could use a callable Cloud Function to read the User Profiles, as you have mentioned. This Cloud Function will:
Fetch the User Profile data;
Increment the profileVisitedCount field (in the User Profile document);
Send back the User Profile data to the client.
You need to deny read access right to the user-profile collection, in order to force the users to "read" it through the Cloud Function.
This way you are sure that the profileVisitedCount fields are only incremented when there is a "real" User Profile read.
Note also that you could still keep the profileVisitsCounters collection if having two different collections brings some extra advantages for your business case. In this case, the Cloud Function would increment the counter in this collection, instead of incrementing it in the User Profile itself. You would restrict the access right of the profileVisitsCounters collection to read only since the Cloud Function bypasses the security rules. (allow read: if true; allow write: if false;).
Finally, note that it might be interesting to read this article, which, among others, details the pros and cons of querying Firebase databases with Cloud Functions.
this is a bit of a composite question, I'll try my best to separate the various parts even if they all have a common intent.
Common intent
Having a clear way of delivering notifications about posts regarding specific topics to Firebase Users (and not simply to application instances).
I have tried various methods, and I can't find a definitive answer about which one is the best one.
Method 1 - Relying only on the database
Each Firebase User has its own document in the Firestore at users/{userId}
This document contains two collections: tokens and interests.
The token collection contains a list of documents which have FCM tokens as one of their fields. Each time an user signs in the application or FirebaseInstanceIDService.onTokenRefresh() is called, the collection is updated to add the new token.
The interest collection contains a list of interests which simply are strings and are used as tags for posts. This collection has a mirror as interests/{interestId}/users/{userId} showing all the users interested in something. (This is kept updated and synchronised via a Cloud Function)
When a new post is created under a specific interest, I can get a list of all the users interested and then get their tokens from their document. Finally, I send a notification to each individual token.
Problems
This solution is not elegant (this isn't that big of a problem)
With the new GDPR rules I fear I might not be allowed to save tokens
directly on the Database
If the user signs out when he's offline, the
token isn't removed from his document, and the new user receives
notifications for the old interests.
Should I keep track of what the current token is and update it each time an user signs in ignoring FirebaseInstanceIDService.onTokenRefresh()? Else only the user signed in when the service is called would update the database.
Method 2 - Using FCM topic subscriptions
This should be the best option for me, but I can't understand how to make it work with multiple users on the same phone (always one at a time though)
The way I would handle this is still have the users/{userId}/interests collection, removing users/{userId}/tokens and interests/{interestId}/users, and subscribe/unsubscribe from the various topics as the user signs in and out.
Problems
What happens if the user signs out when he's offline? There is no way to retrieve the current subscriptions and remove each one, potentially resulting in conflicting topics subscriptions.
Thank you very much for your time