Add keys to Firebase user Object using AngularFire2 - javascript

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.

Related

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.

Firebase Auth Built-in identity

I am building a web platform to connect learners with tutors using Firebase Auth and Firestore. I am storing the learners' user info in a Firestore collection, and the tutor's info in another. I am building a function that can detect if a client is a learner or a tutor upon login.
One solution I was thinking is to query in which collection the user is found using UID. Although, this is a potential solution. But it sounds like it requires a lot of transaction, and may have a long run time if collections get big. Is there something else I can do for that? I am wondering if I can use authentication to build an embedded identity to each user to differentiate between "Tutor" and "Learner"? So each time the user logs in, we know the identity immediately?
I know that in the decoded authentication token, there is info such as this:
{ iss: 'https://securetoken.google.com/xxxx',
aud: 'xxxx',
auth_time: 1569886929,
user_id: 'aB03',
sub: 'aB03',
iat: 1570582588,
exp: 1570586188,
email: 'aa#gmail.com',
email_verified: false,
firebase:
{ identities: { email: [Array] }, sign_in_provider: 'password' },
uid: 'aa3' }
Can I leverage one of these to build what I want?
Really appreciate your time and help.
Since you mention "collection", I assume you're looking to use Firestore. In that case: the size of the collection has no effect on the query performance. No matter if there are 1,000 user documents in the collection, 1,000,000 or even 1,000,000,000, the time it takes to query for a single user document will always be the same.
Aside from that you can also store the user's type in the ID token (which is what you've shown in your question). This is known as a "custom claim", since you're adding a custom property for your app to the information. You'll want to do this from a trusted environment (your development machine, a server you control, or Cloud Functions), as I'd assume users should not be able to change their own role. See the documentation on controlling access with custom claims for more information on this.

Password protect a page with Firebase

I'm building a CMS with Firebase, but struggling to assess whether what I require is possible, or if I'm missing something.
What I require is the ability to password-protect a page only, and remember that browser as having access. A full user account (using the in built auth) is required to edit the content of the page, but only a password is required to view it.
I know I can use the auth flow with email, but am looking for the editor to be able to create a password for viewing only.
Is this possible, or should I look elsewhere?
The way I commonly do this is a bit like Jeremy's answer, but simpler.
You ask the user for a password when they enter the page, and store that password locally (for reloads).
Then you store data in your database under a path that includes the password. So say that your password is geheim, you could store the data under:
data: {
geheim: {
value: "This is the secret value"
}
}
Now you secure your database with rules like these:
{
"rules": {
".read": false,
"data": {
"geheim": {
".read": true
}
}
}
}
Now somebody can only read the data at /data/geheim if they know the entire path. So you'll enter the data part in your code, but require them to enter geheim as the password. Then you attach a listener with:
firebase.database().ref("data").child(password).once("value", function(snapshot) {
console.log(snapshot.val());
});
And if the user entered the correct value for password, this will read the value.
Firebase Authentication only deals with authenticated user accounts. It doesn't deal with simple password protection of content.
It's definitely possible, but as Doug's answer indicated, you'll have to do it outside normal means. Off the top of my head, the way I would accomplish this is...
When a user enters a password, it stores the password in their local storage.
On page load, or on password entry... pull the password from local storage
Make a request to a Firebase cloud function, makes sure to include the password it just retrieved from local storage, and which page it is requesting content for
Firebase cloud function validates password
Firebase cloud function retrieves data for specific page
Firebase cloud function returns said data
Load data on front-end like normal
As you already identified, you should stick with the built-in Firebase auth for content editing.
I definitely suggest Frank's answer because it's simple and it works. Btw the moral of the story is that you use the firebase Database to store you view-only password but, if you want to complicate your life because you need a strong view-only password system, the Authentication product provides the custom authentication method that you can integrate with your existing auth system (for example fb login). It obviously needs a server-side implementation that is a code that takes the password, check if it's valid and sends the token back to the Auth system.
Here more details: https://firebase.google.com/docs/auth/web/custom-auth

Verifying user log email and password by looping through psql table

I am learning to code and am attempting to build a to do web application in node using Express (I think that's the right wording).
I have a table('users') in postgresql which stores user_id,email and password.
When a user logs in to the website I want to loop through the table and ensure the email exists and it matches the password and then the user can log in and when they're logged in - their unique user_id is assigned and brings up their previous to do lists.. I would like to incorporate knex also if possible.
I am at a loss how to do this and would appreciate any tips/pointing in the right direction.
Thanks
Try something basic first
SELECT
user_id
FROM users
WHERE
email = _your_user_email
AND password = _your_user_password;
If the result you get back contains user_id or whatever you want returned, then the user exists. You can expand on this further by checking for email, and let the user know that the email exists but the password is incorrect, etc. Try the simple method first and see if this meet your need.
First of all, I would recommend you to name your id field for your users table as id.
It is best practice to name id fields as id and reference columns as <tablename>_id
(eg. table clothes.id unique identifier for iter and clothes.user_id – foreign key to table users).
Secondly, it is highly NOT recommended to store your passwords as raw data inside of the database (security reasons).
It is a common practice to keep user passwords as hashed data.
For example, take a look at bcrypt package.
To select users (there is no such thing as "loop" in terms of database, it is called "query") you need to
create a query like
select
id,
email,
<any_other_field_you_need>
from
users
where
email = 'your#email.com'
and password = 'your password hash'
In terms of knex it can be written
knex('users')
.select(['id', 'email', '<any_other_field_you_need>'])
.where('email', 'your#email.com')
.where('password', 'your password hash')
Your query params (email, password) you can get from express body.
Make sure you are using POST HTTP method to send your request and pass your data as a body.
In case you don't know express – it's an npm package.
It helps in the creation of web-services. They have a hello world guide on their
official website. Feel free to check it out. Or just simply google "express tutorial for beginner" there are a lot of great tutorials over the internet about it. It's quite popular.

Firebase: setting additional user properties

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.

Categories

Resources