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.
Related
I have this security concern with Firestore. The issue is could a malicious user for example inject data in to his document? Or even Worst having access to different collections? I know rules play a major part in here, but since I am creating docs/updating docs/deleting docs from front end could an abuse for crud happen in the context of the single user?
Also there is another part; I want to create a userSub collection (from front end) it will have a subscription info.
UserSub/uid
Premium: true
Enddate: 2 days form now
Could a malicious user get the uid from authContext and make crud ops to modify the mention doc in the collection to let’s say 10 days from now extending his sub? Since he knows what doc I am creating for those values (from source code in chrome)?
You must not allow users to update their subscription information from client. This should be done from backend only for example, if you use Stripe for payment, you should use their webhooks which would send subscription information to your backend/Cloud function that would update users subscription in your database or Firebase Auth custom claims.
You must ensure that this data is read only from users side using security rules if using database.
I've developed an app which relies on Firestore for storing some user's data. This app doesn't have any login mechanism, as it uses the device UUID as identifier; we're not managing any sensitive data, btw.
I'm getting daily warnings from Firestore regarding the absence of security rules in my database, but as long as I don't have any login mechanism and my users need to both read and write from it, I can't see any way for implementing a useful security rule.
Is there any pattern I could follow in this situation? Is there any way to create a security rule for allowing to only read and write data created by the same user without any user authentication?
Thanks in advance
It sounds like you want to identify the user, but then without authentication. My guess is that you want to identify them, without requiring them to provide credentials.
If that is the case, you're looking for Firebase's anonymous authentication provider, which assigns a unique, unspoofable ID to each app instance. Signing in anonymously takes very little code, for example for Android it's:
FirebaseAuth.getInstance().signInAnonymously();
After this call completes, the user has an ID that you can then use in your security rules to identify the data from this user.
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
I want to know what will happen to the users of my app that I used anonymous sign in method for them.
The Firebase documentation is really BAD and didn't explain everything and expect developer to find out himself.
I found in its old version documentation that anonymous session will expires based on the expiration time has been set in Login & Auth tab, but even there didn't mention this means just the session ends or it means that user id will remove also from my app users list or what EXACTLY happened?
I found this answer but it really is not acceptable. The number of anonymous users will grow very very fast if you do a web app and make every thing hard.
I even cannot see the number of my app users in my dashboard!!!!!
So, what should i do? should i develop a dashboard for my data myself or Firebase team should do it? At least for managing users i should have more power than just searching user with their email and when you use custom login you cannot do this also.
Anonymous users don't expire, and there isn't currently any automated way to purge them.
Firebase doesn't automatically remove them because it doesn't really know if a user is still storing data linked to that login - only the app creator does. Imagine if you are playing a puzzle game on your phone, and get to level 100. Then when you go to play level 101 next year, all progress is lost. Firebase can't just assume a user being inactive for a year means that the account can be removed.
There is a couple tools that should help, though.
1) Admin SDK & Firebase CLI list users.
2) Linking multiple auth providers
3) Auth State Persistence
Once you list your users, you can check that each doesn't have any other providers, and hasn't been used recently, doesn't have data stored, and delete them.
Better, though, would be to ensure that only one account is created per user. If you create an anonymous account to help users store data before logging in, you may want to consider prompting them to link a auth provider (like Google or email). If you link the account, rather than creating a new one, you'll avoid abandoned accounts from active users.
In general, you will also want to make sure to use auth state persistence to ensure that there aren't more accounts than necessary being created. Creating 1 account per new visitor, rather than 1 per time someone repeatedly visits your page, will significantly help keep user growth in check.
In my case, I am using the anonymous sign-in method for authentication without the knowledge of the user.
Each time when the user leaves the app, delete the anonymous user by -
FirebaseAuth.getinstance().currentuser?.delete()
There will be no stacking up of anonymous user with this and limits the number of anonymous user in the app
2023 update
Firebase has automatic clean up now.
If you've upgraded your project to Firebase
Authentication with Identity Platform, you can enable automatic
clean-up in the Firebase console. When you enable this feature you
allow, Firebase to automatically delete anonymous accounts older than
30 days. In projects with automatic clean-up enabled, anonymous
authentication will not count toward usage limits or billing quotas.
Any anonymous accounts created after enabling automatic clean-up might
be automatically deleted any time after 30 days post-creation.
Anonymous accounts created before enabling automatic clean-up will be
eligible for automatic deletion starting 30 days after enabling
automatic clean-up. If you turn automatic clean-up off, any anonymous
accounts scheduled to be deleted will remain scheduled to be deleted.
These accounts do not count toward usage limits or billing quotas. If
you "upgrade" an anonymous account by linking it to any sign-in
method, the account will not get automatically deleted. If you want to
see how many users will be affected before you enable this feature,
and you've upgraded your project to Firebase Authentication with
Identity Platform, you can filter by is_anon in Cloud Logging.
Docs
There is a possible cloud function for that.
Check: delete-unused-accounts-cron
This function deletes unused accounts after a certain time. Which might be also helpfull for nonanonymous users.
If you only want to delete anonymous users or check only for them (for example delete after a different inactive time than normal users) you can identify them by checking:
const inactiveUsers = result.users.filter(
user => {
isAnonymous = user.providerData.length == 0;
//do something when anonymous
});
If you'd like anonymous users to be removed from your user list, you'll have to write a service to do that for you.
Since firebase doesn't provide a way to list registered users, you'll have to make sure you're storing some sort of user list in the database. You can then use the node.js admin sdk to get user data, check if the user is anonymous, and find when the user was created. For performance reasons, you may wish to store this information in a special area of your database and retrieve it all at once. Once you've identified a stale anonymous user they can be easily deleted.
What's the best way to set permissions on objects in Apigee BAAS entities, collections in such a way that Users can edit what they create, and others can read them? There might be a case for Admins to be able to edit everything as well.
I asked a similar question here Securing apigee baas that was more around securing the app id/secret which would be needed to make the call to update permissions, but I was wondering if there is any best practice around doing this sort of thing from a mobile application.
My initial thought would still be the service callout (not sure how Apigee-127 which was mentioned in the previous question would be any different to a service callout directly to the BAAS as to me 127 looks like I'm just writing my apis in Node.js rather than using the edge console), but I don't know if there is an easier way in terms of securing all entities, in specific collections ,created by specific users? I guess I could add a created by column which I could check from an app perspective, but this wouldn't stop someone from potentially hitting the BAAS directly and retrieving this info unless permissions are also set at an entity level requiring a user access token.
Is it possible to secure the BAAS in such a way that only calls from Edge can hit the BAAS url?
(Disclaimer: I have not tried this myself but here is a suggestion.)
API BaaS Automatically sets the path segment to the UUID of the currently authenticated user when $user is used. For example, if you sent a request with a valid access token for a user with UUID bd397ea1-a71c-3249-8a4c-62fd53c78ce7, the path /users/${user} would be interpreted as /users/bd397ea1-a71c-3249-8a4c-62fd53c78ce7, assigning the permission only to that user entity.
In this way, through your application, you can set permission for each user, and each object as soon as the objects are created from your application. Assuming you have the user authenticated, of course.
Ref: http://apigee.com/docs/api-baas/content/using-permissions