Firebase: setting additional user properties - javascript

I'd like to add a property to a Firebase user object. The user documentation says that I can only store additional properties using the Firebase real time database.
I am unsure on how this can works in practice.
What does the following mean in practice?
You cannot add other properties to the Firebase User object directly;
instead, you can store the additional properties in your Firebase
Realtime Database.
I interpret it as following:
"you cannot modify properties of a FIRUser object but you can combine this with additional objects"
I found the set function documentation which I interpet in this way:
var userRef = ref.child("users");
userRef.set({
newfield: "value"
});
Is this a sensible approach?

You're almost there. In the legacy Firebase documentation, we had a section on storing such additional user data.
The key is to store the additional information under the user's uid:
let newUser = [
"provider": authData.provider,
"displayName": authData.providerData["displayName"] as? NSString as? String
]
// Create a child path with a key set to the uid underneath the "users" node
// This creates a URL path like the following:
// - https://<YOUR-FIREBASE-APP>.firebaseio.com/users/<uid>
ref.childByAppendingPath("users")
.childByAppendingPath(authData.uid).setValue(newUser)
I've added a note that we should add this information in the new documentation too. We just need to find a good spot for it.

According to the Custom Claims documentation,
The Firebase Admin SDK supports defining custom attributes on user accounts. [...] User roles can be defined for the following common cases:
Add an additional identifier on a user. For example, a Firebase user could map to a different UID in another system.
[...] Custom claims payload must not exceed 1000 bytes.
However, do this only for authentication-related user data, not for general profile information, per the Best Practices:
Custom claims are only used to provide access control. They are not designed to store additional data (such as profile and other custom data). While this may seem like a convenient mechanism to do so, it is strongly discouraged as these claims are stored in the ID token and could cause performance issues because all authenticated requests always contain a Firebase ID token corresponding to the signed in user.
Use custom claims to store data for controlling user access only. All other data should be stored separately via the real-time database or other server side storage.

Related

User specific firebase functions secrets

I need some help (more of an advice), basically I have an app in which user can purchase scratch-cards, when purchased, user will have an option to activate it, after activating, the encrypted scratch-card url gets decrypted (done by me), and now I replace the encrypted url with this newly activated decrypted url in my firestore collection, but to add more security I wanted to store it as a firebase functions secret (as I'm using firebase and its cloud functions), so I'm confused as to how do I manage it and store user specific decrypted url in firebase functions secrets, because as per the documentation https://firebase.google.com/docs/functions/config-env it looks like we can only store a single secret value like this: firebase functions:secrets:set SECRET_NAME but I want it to be user specific because for each user, there could be many scratch-cards and their decrypted url, I do not want them to store as it is inside my firestore collection, I want it to store in firebase functions secrets.
For example, I have user collection:
users/12345/
-> decryptedURL:some_link_to_firebase_secret
So, this some_link_to_firebase_secret could be a url from which a user can get the decrypted URL from firebase functions secrets, and it should belong to only this specific user. Is it possible? Or any other approach?
Can someone help me with this? Thank you.
Secrets are for storing developer-secrets not user-secrets. For storing secret values from the user, use a database and its security mechanism. For example, if you store the value in one of Firebase's databases (Firestore or the Realtime Database) you'd use security rules to ensure the user can't read them.

How can I construct a user from a user json?

I am using the CDN import method for SDK v9. I would like to know, given that I have a JSON-serializable representation of a user object, how can I construct a user object, so that I can use it with methods like updateCurrentUser.
If there was a way that I could access the UserImpl class like you can with npm
import { UserImpl } from '#firebase/auth/internal';
I'd be able to do this. However, I am stuck with the CDN import method, which doesn't allow access to the UserImpl class.
I understand that this may be a strange question, but understand that the way this is set up, once the user logs in, its json representation is saved elsewhere and the user object itself is lost.
I guess a better question would be, how can I deserialize a user?
An important piece of information here is that I want to be able able to deserialize users that once logged in. At some point of the app's lifetime, a user logs in(multiple users might log in and out), the user object is lost, and its json representation is saved elsewhere. I need to be able to retrieve the user object from its json representation later.
A potential workaround that seems to work at first glance, is to save a few informations from the first user that ever logs in:
const userInfo = {}
Object.setPrototypeOf(userInfo.stsTokenManager, auth.currentUser.stsTokenManager.constructor.prototype)
userInfo._clone = auth.currentUser._clone;
userInfo.auth = auth.currentUser.auth;
//and then I apply this to any user json I need to later on
user._clone = userInfo._clone;
user.auth = userInfo.auth;
user.stsTokenManager = userInfo.stsTokenManager;
//if I add the _clone,auth and stsTokenManager,I don't get errors andthe
//user json seems to become a user object for all intents and purposes,
//however I don't know if this is very safe and works in all situations.
//would applying the same clone,auth and tokenManager to all json users
//work?
Unfortunately, using the firebase admin sdk is also not an option because this is a client side app.
Is there any better solution? Thank you for your time.

Getting a sub-collection by a specific field value in Firestore

How do I find a subcollection based on a field value? I am currently using this code but it doesnt work:
var user = db()
.collection('myCollection')
.doc()
.collection('private')
.where("nam", "==", this.state.passcode);
What I am trying to achieve is making a custom authentication, so giving a custom username and password to users (in this case just a passcode). So I decided to store those credentials in a separate sub-collection inside a document. How can a user authenticate by comparing the values of username and password with the ones of a sub-collection?
Another question, is sub-collection for credentials a good idea? Will it cost the same to me as if I would store those info in the document?
First of all, what you're doing right now is not secure at all. You should never store user credentials in a database, especially not one that's directly accessible to your web and mobile clients. To do this properly, you should be making use of Firebase Authentication to sign in users. (You tagged this question firebase-authentication, which refers to that product.) In fact, doing security properly is very difficult. Firebase Auth will make sure everything is done correctly.
Secondly, the query you have now will never yield any documents. That's because you're not passing anything to doc(), which means it will return a DocumentReference to a non-existent document with a random ID. If you meant to have some sort of unique identifier for each user, perhaps that's something you would want to pass to doc() so that each user's subcollection would be correctly identified.

Add keys to Firebase user Object using AngularFire2

I'm trying to implement a role system with Firebase and at least I did it creating a collection into my database and comparing the actual uid vs the table (more or less).
But my question is if it's possible to set any property in the Firebase User object, like role: 'foo'. It's more a theoretical question.
Let's say that I create a user programmatically, like:
this.af.auth.createUser({ 'email': email, 'password': password })
.then(createdUser => {
...
createdUser['role'] = foo;
...... // How can I update the Firebase users database with this new user?
})
.catch(err => console.log(err));
I was watching around for some answer but nothing appears. Can anyone bring me some help?
Thanks!
The only secure way to add such roles to your user object is by using custom authentication, where you fully control the contents of the user JWT.
Most developers take an alternative route, where they store information about their users and roles in the Firebase Database and then secure data access through security rules. I recommend reading this blog post about implementing group security, and some of the results in this query.

Is there a way to secure my geopoint while still permitting Parse.com "near" queries?

I'm working on an application that allows users to save objects, and then view objects from other users near them. I store a geopoint on the Parse.User object, and have written a query that finds other users near the current user, and then objects that belong to those users:
var user = Parse.User.current();
var innerQuery = new Parse.Query(Parse.User);
innerQuery.near("location", user.get("location"));
innerQuery.notEqualTo("objectId", user.id);
var query = new Parse.Query(MyObject);
query.include(innerQuery);
query.matchesQuery("user", innerQuery);
return query.find()
This works great. However, I'm trying to secure user information–I don't want other users to be able to simply call user.get("location") and get the precise coordinates (and therefore address) of another user.
I tried setting the CLP to the _User table to prohibit reads and writes, but then my query fails with 403 (Forbidden).
Is there a way to secure my geopoint while still permitting near queries?
Your inner query works because the User class is by default publicly readable. The downside is that you lose the ability to protect the data you put in there as long as you have the find CLP on your class. The easiest solution is to move your searching query to Cloud while disabling find permission in your User class CLP to protect the data from being searched which includes in your case a user's location.

Categories

Resources