I am struggling with the docs for Firebase, Google Cloud etc. I notice I often get stuck on this notation. There must be something I do not know about it or have forgotten.
For example this page admin.auth.UserInfo tells me I can get info about the user (email etc). But after reading the page I still don't know how. What am I missing?
PS: I believe I know that admin comes from this but it does not help me:
const admin = require("firebase-admin");
When using the Admin SDK, to get information about a user, call admin.auth().getUser(uid). An example is provided in the documentation.
getUser() returns a UserRecord. It contains an number of properties, including providerData, which is an array of UserInfo.
Each client SDK provides methods to obtain the UID of an authorized user. For example, on Android it's FirebaseAuth.getInstance().getCurrentUser().getUid() (example here).
The UID of each user for a project is available in the Authorization panel of the Firebase Console.
In your example you are reading the documentation of an interface. It defines what UserInfo has.
If you want to access to a method, for example for reading userInfo, first you have to access to auth service using admin.auth().<method>.
If you want more info about how to use it, see https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth
Related
I'm using FireAuth to sign up my users, but i'm not using FireCloud (because we use our own back-end cloud database), and I would like to know if when a user connect with Google Sign In, if it is the first time or not he connect (to know if it create the user an account or simply log into one).
I've found this on the documentation of Firebase, it look perfect, but it's in beta and I don't seem to find the correct method with the dart package.
https://firebase.google.com/docs/functions/auth-events
Hope you can help me !
Thanks you for reading !
You can use isNewUser, which will return if the user is logging in for the first time:
AuthResult user = await auth.signInWithCredential(credential);
print(user.additionalUserInfo.isNewUser);
https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth/lib/src/additional_user_info.dart
I'm trying to get the UID of the user authenticated by firebase web sdk, in the cloud function. The cloud function is triggered by onWrite event of cloud firestore.
This function is triggered when the logged in user is creating/updating items to the cafe. The authentication is handled by Firebase Auth. The security rules enable write only for logged in users. So this event could be tied to a user.
export const cfun = functions.firestore.document('cafes/{cafeId}/items/{itemId}').onWrite(async event => {
// trying to get the uid here
})
There are examples in the docs that deals with the userId, but in all those cases the userId is part of the document path. But in this model the user is not part of the path, as a cafe could have multiple owners and so could be manipulated by many users. So adding userId to the path is not an option.
It looks like a common case for serverless architecture.
#
Update: Functions triggered by firestore doesn't have event.auth populated. Looking for suggestions on modelling the following requirement.
In the data-model, I've got cafes and owners. Each cafe could be owned by many owners and a cafe could be transferred to some-other owner at a later stage. So the cafes are modelled as /cafes/{cafeId} and everything that belongs to the cafe as /cafes/{cafeId}/items/{itemId} etc.
We also need to query cafes based on different params, if modelled below users it becomes difficult. For these reasons the cafe cannot be modelled as /users/{userId}/cafes/{cafeId}.
As far as security rules are concerned, I could control write access using get(<>) to determine who gets write access to cafes. There is no problem with the security.
I feel that the execution context should provide all available information and let the developers handle it appropriate for their use case. And for serverless apps userId is a must.
If event.auth is not provided in the function, then this restriction will force items that does not belong to users to be modelled /users/{userId}/<item_name>/{itemId} just for the sake of accessing the userId in the cloud functions. This doesn't feel natural.
Also right now there is no way to figure if the cloud function is triggered because of the changes performed in the console. The event.auth info that is available for firebase database triggered functions will be perfect to handle all cases.
Any suggestions regarding how to remodel this case is appreciated as well.
#
Thanks in advance,
I have been facing a similar issue. In Firebase, it was easy - you simply took the data from event.auth. I would assume this is simply a feature not implemented yet while we are in the beta phase of Firestore. Adding the user id to the path does not work as you previously mentioned as it will constantly be changing depending on the user making the update.
My scenario is that I want to create a "lastUpdatedBy" field in the object being updated. If we were to allow the client to send in a lastUpdatedBy field in the payload, this could be abused by a rogue client (i.e. someone with a authenticated account) trying to impersonate someone else. Therefore in Firebase we relied on a cloud function to populate this field on data change events.
My workaround is to allow the client to insert the "lastUpdatedBy" field but additionally use the Firestore rules to validate that the userId in the payload matches that of the logged in user - otherwise deny the write request.
Something like:
match /collectionA/{docId} {
allow update: if request.resource.data.lastUpdatedBy == request.auth.uid;
}
Until Google/Firestore guys add the "auth" object to the cloud function I don't see any other workaround but would love to hear differently.
Since Cloud Functions 1.0 you can get the UID like this
exports.dbCreate = functions.database.ref('/path').onCreate((snap, context) => {
const uid = context.auth.uid;
const authVar = context.auth;
});
Here is a nice post from the FB team for all CF1.0 changes: https://firebase.google.com/docs/functions/beta-v1-diff#event_parameter_split_into_data_and_context
The data of context.auth can be found here: https://firebase.google.com/docs/firestore/reference/security/#properties
I have an app created with Firebase real-time database and I've created a few users, all with REST methods found here: https://firebase.google.com/docs/reference/rest/auth/
I can get the user info for the current user, but I would like to have a REST endpoint to fetch all the users (UID, email, displayPhoto, name, etc) or at least a user by UID. I haven't found this method in the link above.
I know that there is an SDK to do that (https://firebase.google.com/docs/auth/admin/manage-users), but I would like to do this with REST since the full app is using REST.
Does anybody know if this is possible and has the rest endpoint?
Thank you!
There is no public REST API to get a list of all users. The reason for this is that getting a list of users is considered a sensitive operation, and allowing that from client-side code would be risky.
The common way to implement your use-case is to build your own endpoint, either on a server you already control, or with Cloud Functions. There you can use the Admin SDK to get the list of users, and then return that to your caller. Make sure to limit what data you return and to properly secure that endpoint though, as otherwise you'll be putting your user's information at risk.
Somehow I still have a understanding problem with firebase rules and need some input from you guys.
Lets say I have a user node with all my users. Each user contain sub-nodes for things like email, name, phone etc.
My basic firebase rule says now that only the user with the correct id can edit/write/read in his own node. This works all fine. But now I do have situations like another user search for a friend and there for I need to search for example in all my users for a name or email BUT since my rule does not allow to read userdata except if the user is the owner of his own data I dont know how to solve this. I cant use a rule to give every authenticated user READ rights for the other users data BUT I still would like to search for example for a email address in the other users data. This confuses me all a lot.
The only thing I can think of is to run parallel a complete separated list with something like public informations and keep the rule that everybody can read (not write) in this list. BUT THEN again I have the issue that somebody could easy access my entire user-list (emails for example) if I keep them inside the public list.
I would be happy if somebody can point me into the right direction. I have no idea where to start to set this up from the start correct.
What is the best approach to do something like this?
Hey I'm not a pro or affiliated with Firebase. But as I have encountered same type of problems I share my thoughts with you.
I don't think allowing users to search others based on emails stored in a Firebase node and directly from client side is entirely safe. Searching based on somethign like userName is ok because it is scoped to your app.
If you must, then I would either make it a 2 step process using Firebase functions (which you can put another layer of security check in there also no user is directly reading from database) or introduce other parameters that all need to pass for a successful query. Something like a temporary unique id that expires after awhile.
If you still want to share emails, you can store user's sensitive information in a separate node and only save what you really need to expose to others in a public node which can still have some security rules protecting it form access of someone who is not logged in, for instance and you map the emails by UIDs.
Just some thoughts.
EDITS
You can provide a way for users to be able to search others by username (similar to instagram for instance.) and in firebase you only have to connect each username with their UID. So people can find each other via username. Imagine this in firebase (you can do the same of emails so a person making request need to know an email to get UID not the other way) :
user_names : {
alice_d: UID,
bob_ross: UID,
....
}
You can later search for any user name without exposing others simply by using .equalTo() in your query or run more complex queries via FireStore (I am new to it too) or using a search system that has your data indexed already like Algolia.
Facebook provides further information such as list of friends if you app is approved so you can always use that list to suggest friends granted that users have logged in by Facebook O'auth and your app has the priviledge to see friends lists.
See here for how to verify a user making https requests in Firebase functions. In your function you can do the search and only return what is safe back to the client. (keep in mind the speed might be an issue unless your function is running frequently). And for making the request from client side, you do something like this.
_makeRequest: function() {
this.user.getIdToken().then(function(token) {
//token is a long string JWT token used to identify the user to a Firebase service.
var req = new XMLHttpRequest();
req.onload = function() {
/*you return the result in your function*/
if (JSON.parse(req.responseText).rslt === "SUCCESS") {
}
}.bind(this);
req.onerror = function() {
}.bind(this);
/*attaching location key*/
req.open('GET', 'https://us-central1-rest-of-function-address-found-in-
firebase-functions', true);
req.setRequestHeader('Authorization', 'Bearer ' + token);
req.send();
}
You can also make this happen by writing something to database and have a function to run onCreate(), see here if you need more info on Firebase functions. Hope this helps.
If you want to allow any user to find any other user by their email address, that means that users must be able to read email addresses. If you don't want them to be able to read the full profiles, you'll want to set up an extra data structure that maps email addresses to UIDs:
emails: {
"theeben#domain,com": "uid5601401",
"puf#theotherdomain,com": "uid209103"
}
With this structure you're only exposing the email addresses.
But to be honest, that is still exposing quite some information about all users. Nowadays, I'd consider implementing the search using Cloud Functions for Firebase. That way your API is a function findUser(email): uid type function, exposing only the minimal information.
I'm trying to get the UID of the user authenticated by firebase web sdk, in the cloud function. The cloud function is triggered by onWrite event of cloud firestore.
This function is triggered when the logged in user is creating/updating items to the cafe. The authentication is handled by Firebase Auth. The security rules enable write only for logged in users. So this event could be tied to a user.
export const cfun = functions.firestore.document('cafes/{cafeId}/items/{itemId}').onWrite(async event => {
// trying to get the uid here
})
There are examples in the docs that deals with the userId, but in all those cases the userId is part of the document path. But in this model the user is not part of the path, as a cafe could have multiple owners and so could be manipulated by many users. So adding userId to the path is not an option.
It looks like a common case for serverless architecture.
#
Update: Functions triggered by firestore doesn't have event.auth populated. Looking for suggestions on modelling the following requirement.
In the data-model, I've got cafes and owners. Each cafe could be owned by many owners and a cafe could be transferred to some-other owner at a later stage. So the cafes are modelled as /cafes/{cafeId} and everything that belongs to the cafe as /cafes/{cafeId}/items/{itemId} etc.
We also need to query cafes based on different params, if modelled below users it becomes difficult. For these reasons the cafe cannot be modelled as /users/{userId}/cafes/{cafeId}.
As far as security rules are concerned, I could control write access using get(<>) to determine who gets write access to cafes. There is no problem with the security.
I feel that the execution context should provide all available information and let the developers handle it appropriate for their use case. And for serverless apps userId is a must.
If event.auth is not provided in the function, then this restriction will force items that does not belong to users to be modelled /users/{userId}/<item_name>/{itemId} just for the sake of accessing the userId in the cloud functions. This doesn't feel natural.
Also right now there is no way to figure if the cloud function is triggered because of the changes performed in the console. The event.auth info that is available for firebase database triggered functions will be perfect to handle all cases.
Any suggestions regarding how to remodel this case is appreciated as well.
#
Thanks in advance,
I have been facing a similar issue. In Firebase, it was easy - you simply took the data from event.auth. I would assume this is simply a feature not implemented yet while we are in the beta phase of Firestore. Adding the user id to the path does not work as you previously mentioned as it will constantly be changing depending on the user making the update.
My scenario is that I want to create a "lastUpdatedBy" field in the object being updated. If we were to allow the client to send in a lastUpdatedBy field in the payload, this could be abused by a rogue client (i.e. someone with a authenticated account) trying to impersonate someone else. Therefore in Firebase we relied on a cloud function to populate this field on data change events.
My workaround is to allow the client to insert the "lastUpdatedBy" field but additionally use the Firestore rules to validate that the userId in the payload matches that of the logged in user - otherwise deny the write request.
Something like:
match /collectionA/{docId} {
allow update: if request.resource.data.lastUpdatedBy == request.auth.uid;
}
Until Google/Firestore guys add the "auth" object to the cloud function I don't see any other workaround but would love to hear differently.
Since Cloud Functions 1.0 you can get the UID like this
exports.dbCreate = functions.database.ref('/path').onCreate((snap, context) => {
const uid = context.auth.uid;
const authVar = context.auth;
});
Here is a nice post from the FB team for all CF1.0 changes: https://firebase.google.com/docs/functions/beta-v1-diff#event_parameter_split_into_data_and_context
The data of context.auth can be found here: https://firebase.google.com/docs/firestore/reference/security/#properties