how to make singups and signins with different group of users - firebase

I am developing an app for my college and there are different types of users called students ,teachers , hod's
etc. When they login, how do I know a teacher logged in, or a student logged in? Is there any function in firestore for role based signups and signins?
I was thinking that when a teacher signs up, I will add a tag end of her uid.username that if username is 'DANIEL' while signup, I will add a tea for teachers and stu for students at the end of the name what they provided.
So when they login i will get the uid and do the string manupulations and get the last three letters so that i can know who logged in so that i can show different UI to Different types of users
Is there any best way to do like this ?
while singning up user enters his username example:"daniel"
i will update that username in uid.username like this "daniel-stu"(if student signed up),"daniel-tea" if techer signsup.

Storing this information in the user's display name can work. You can read it back from there next time, and take action in your application's client-side code. But note that this means that any user can change their role, since they can also call the same code to update their profile. If that is not a concern for your app, then this approach sounds like it would work.
If malicious users should not be able to change their role, then you shouldn't set that role from the client-side application code. In that case, you can set the role from a server (or your development machine, or Cloud Functions) using the Admin SDK. Since the Admin SDK runs in a trusted environment, it has expanded privileges and can update the profile of any user. So the Admin SDK could update the display name of the user in the same way you have in mind.
But this still isn't secure, since you're still setting a property that anyone can modify for their own profile. Again... if that is no problem for your app that is fine, but if the use-case requires that you can rely on the property to be correct, we have to keep looking elsewhere.
The Admin SDK can set additional so-called claims on a user profile that client-side code can't modify. Such claims are for things that affect the permissions of the user, such if the user is an admin, or what role/group your users belong to. This sounds quite close to what you are describing, so can also be used. And this time, only your code that runs in a trusted environment will be able to do so.
Finally, you could store the additional information about a user in the database. It's quite common to have a collection (Users or Profiles) in the database, where you store a document for each user (with the document name being User.uid). You create the document when the user first signs in, and update whenever you need to. You can do this from the client-side code (if there is no need to control what gets written), or from code that runs in a trusted environment (such as your development machine, a server you control, or Cloud Functions) if you do need to keep control. A big advantage of this approach is that all users can potentially see the information in this collection, where the client-side Authentication SDK only allows a user to read their own user profile.
For more on this, see:
Adding new data to firebase users (in which I essentially list the same options with fewer words)
Add extra User Information with firebase (store the information in the realtime database)
Associate Firebase Users to Database Records (also using the realtime database for the additional information)
Cloud Firestore saving additional user data
this video explaining custom claims
and many more previous questions on this topic

Related

Have one user signup another user with custom fields in firebase/flutter

I am trying to determine if the following scenario is possible with flutter and firebase:
we have users within the company who will be given access to the app, where on the homepage will be a signup another user button where they enter in that user's email and password, they get signed up, and then the original user specifies custom fields for the 2nd user, such as company name, role, position, etc.
Is this possible with flutter and firebase?
Have asked the flutter google group and was told about custom authentications, but from what I see that is just an external authentication system and doesn't show me how to let one user create another users profile with fields.
Any ideas?
The first thing to consider is whether those properties need to be in the user profile at all. The user profile is sent with every request, and should only contain information that is relevant for securing access. If you have additional information to store about the user, you should store it elsewhere (such as in one of Firebase's databases) using the UID of each user as its key.
Assuming that the information is about security (such as the role seems to be, there is no secure way to let one user set security properties (typically referred to as claims) from client-side code. As soon as this is allowed from client-side code, anyone could set such properties for anyone else. That's why setting custom claims for a user is only possible with Firebase's Admin SDKs, which are designed to run in a trusted environment - such as your development machine, a server you control, or Cloud Functions.
There are a few other options, but it's important to realize they're all implemented on top of the above approach.
There is an experimental extension that allows you to set auth claims by writing a document into Firestore, which something like this (JavaScript syntax, but the Flutter code will be similar):
db.collection("user_claims")
.doc("abc123")
.set({
role: "admin",
groups: ["example1", "example2"],
});
Now of course you'll want to make sure that you secure writing to the user_claims collection, as otherwise you'll end up with the same security risk I mentioned in the first paragraph, where everyone can claim any role they want.
Alternatively you can write your own server-side API (for example on Cloud Functions) that you expose to your application, and that then calls the Admin SDK. Here too, it is important to secure access to this API, to ensure only authorized users can call it.

Do users need to create an account to read/write to Firebase

I'm making an app that has Firebase as its database. The app shouldn't need the user to create an account to use it, but I want the user to be able to read/write their data onto the database (so maybe they have to create an account?).
Do I have to make the users create an account in order to use Firebase?
My problem is that my security rules are read/write are allowed for everyone (which I know is wrong, but how do I change them and not need users to create an account?) Maybe that's the issue.
It is best to ask them to create an account
Although:
it can be a non-real email address and
there is anonymous auth also available
It sounds like you need the app to remember that user's particular data, so that when they return to the app, it is still their data (and not someone else's) that is being accessed.
To achieve that, we need each person's data to be stored in a different place in Firebase. Traditionally, this is by having them log in to some kind of system, most conveniently Firebase itself, and then the data stored in a branch of the database defined by their user Id.
Without logging in, you could simply ask the user for an identifier, such as "Bob" or "Carol", and then store their data under their identifier. The Firebase database would therefore have the following structure.
users/Bob/highScore: 3000
users/Bob/level: 7
users/Carol/highScore: 5050
users/Carol/level: 9
However this is not secure because there is nothing stopping Carol coming to the app and saying she is "Bob". Any such client-side activity you carry out to attempt to identify the user is not really authentication (in the opinion of Firebase) because all client-side activities can be faked relatively easily.
Firebase Authentication
The standard solution is to use Firebase to authenticate each user (see the Firebase authentication docs for this), and give your app a user Id (such as "8769dsg6f8g7698769876sdgs9") which is unique and known (by Firebase) to be correct.
Firebase security rules
You can then lock down the database using Firebase Security Rules so that only user 8769dsg6f8g7698769876sdgs9 can write to any of the users/8769dsg6f8g7698769876sdgs9/.... part of the database.
If you don't use Firebase to authenticate the user, Firebase will treat the user as unauthenticated and you will have no way to restrict each user to their own section of the database. Either you leave it wide open (to hackers etc!) or users will not be able to access their own personal data on it.
They can use a FAKE email address and password
If your concern is that they won't want to give out their real email address, you can ask them to make up any email address, e.g. mickeyMouse49857430679304#hotmail.com, and set a password. There is no obligation on your app to contact them on that email address or verify that the email address is correct.
Whenever they come back to the app, or access it on another device, they need to remember the fake email address and password.
Of course, if they lose their password, there is no way to reset it.
Anonymous Authentication, but at risk of losing access
The legendary Frank von Puffelen of Firebase, himself, has added a remark about Anonymous Authentication, in the comments below. From what I understand, this avoids them having to make up a fake email address.
I think the weakness of this is that if they lose their local web storage (e.g. if they manually wipe it, or move to another device), there is no way for them to re-access the same account, unless they have planned ahead by adding an email/pw to the anonymous account.
The only real way to have security per-user data storage is to use Firebase Auth to sign in the user, and write security rules to protect the database so that each user can only access their own data. There are no secure alternatives to this for Realtime Database.

FirebaseAuth signin vs linking an anonymous user

We login users anonymously in our app using FirebaseAuth, and allow them a read-only access to some of our content. At a later point of time the user can decide to login with credentials and have access to more stuff and write user specific data. The question is, do we gain anything by linking the anonymous user with the one with credentials?
Since we do not have any user specific data when the user is anonymous, it looks like a performance overhead (linking and merging seem to be slower) to link/merge as opposed to a plain sign in. Is there a downside to not linking in this scenario?
You will end up with a lot of stale/abandoned anonymous user accounts and if you are saving anonymous user keyed data in your database, that will also need to be cleaned up if you choose to sign in instead of linking.
In that case (sign in instead of linking), you should consider deleting that anonymous user's data.
If you decide the linking flow, you will not run into the above.

Using Dynamic Links to Accept Invites

Before I go into the issue I am having I'd like to provide you with some context. Currently I have users and sessions. Users are the what you would normally think of when you think of users, however sessions can be thought of as meetings. These meetings can be marked as private, in which case I have Firebase Database security rules in place which prevent users from reading and writing to the meeting unless they are a part of it. In app invites are the only way to get invited (originating from the organizer)
Until Now, here's the problem: I would like to use Dynamic links to invite users to sessions by linking straight to the session, however I don't know how I would model this in database security rules.
Does anyone have any idea how I would say: "Anyone that was invited here from a dynamic link has access to invite themselves to a session"? In this case I guess the issue is that I don't know who the user will invite.
Looks like I solved my own problem using my previous comment. I decided to generate a new push key and distribute the key using dynamic links.
What does this look like in the DB?
I created a path in firebase to hold the session's random key:
dynamicInvites/sessions/{sessionId}
"somerandomkey"
and a path to hold the key distributed to users
dynamicInvites/users/{userId}
{
"somerandomkey": {timestamp}
}
In addition there are security rules that say that session X and random key for session X cannot be read unless user A has the random push key for session X or they are a member of the session.
How did you distribute the key?
Since users of the session have access to the random key they can generate a dynamic link with the random key and sessionId as querystrings.
When the user clicks the link they are redirected to the app which pulls the random key and session id from the link and puts the random key under their dynamicinvites user path along with the current time and then opens the session using the session id. The current time is used in the event that I want to perform some type of periodic cleanup of these keys.
Why use a separate push key and not the one from the session?
The push key for the session is in multiple places in the DB and is not considered private as it may be loaded to the client.
Performing a DB update at app startup is not user friendly though
I masked this time using a splash screen when the user clicks the link. Since I have a splash screen at normal startup time this is the normal behavior that users will expect.

Firebase References - Local Authentication

When I create a firebase reference and take a snapshot of that reference while authenticated through firebase authentication then I log out, that data remains.
Requirements:
Page cannot be reloaded or force reloaded after logout
Cannot Clear Firebase Session or all data will need to be reloaded
Must clear only the data that was accessable to the user and not to the public
Must also reload data that is owned or is in the same group as the non-escalated or guest user after the other user has logged out.
I am considering creating objects that wrap my references that will supply a user group and other permissions property as is commonly seen on linux. This will allow me to use the current user object that provides group and user details as a base for deactivating or clearing local data.
Is there a standard way of doing this?
Am I making more work of this than is needed?
I will be hardcoding the knowledge of what groups have permission on the clientside to be replaced later with metadata provided by firebase. I plan to eventually keep track of all references available to a specific user under the user id as well as keep track of the references available publicly and as well again keep track of references available to specific groups where the highest permissions takes priority.
Step one I am taking is creating a way to manage the references clientside and build in checks for authentication change and then utilizing the user details provided in the current auth apply needed changes with authenitication change kicks off. Is it easier to just initiate another call to the server for that snapshot, will that snapshot change if it is no longer authorized?
You control your own app and the prefs based snapshot (or wherever else you save the data) is under your app control as well. Assuming that whatever local storage is protected to your app only (whether natively by Android OS such as private prefs or otherwise), you can simply save the local cache under the user id of the currently authenticated user. So your app can check if the authenticated user matches that user id of the cache and if it does not, then access is denied. In fact, the local cache should be keyed minimally by the logged-in user so you get that kind of check for free (basically the snapshot data won't be found).

Resources