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.
Related
I was wondering if the client would be able to change the user object from null to some value (through the console) and gain access to authenticated resources without having to sign in.
I understand that you can use the following code:
auth.onAuthStateChanged(user => {
if (user) {
console.log("user signed in")
console.log(user)
} else {
console.log("user has signed out")
}
});
How does firebase counteract the client attempting to change the user object?
Is there a more secure way of handling this if this is an issue?
How would I implement it?
Thanks.
Changing the user object in the code you shared does not give the user access to additional information in the Firebase Realtime Database.
Inside the security rules for your database, information about the user is exposed through the auth variable. This variable is populated by Firebase from the ID token of the user that makes a request to the database, and it cannot be spoofed by regular users.
So while the user may change the user variable in your client-side code, this does not impact the auth variable in your server-side security rules. This is one of the reasons why it's important to secure data access server-side (like in security rules) and not just client-side.
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.
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
In token based authentication the user is to validate himself or herself through some form of validation in the form of username and password.The server needs to validate user credentials. Once the server validates user credentials, then the server will issue a signed token to user.Here the server can make use of the secret to generate a token.
I am giving a secret key in some config.js file
module.exports = {
'secretKey': '12345-67890-09876-54321',
'mongoUrl' : 'mongodb://localhost:27017/conFusion'
}
So what I want to know is how a server can make use of this secret key to create and verify JSON web tokens...
There are many articles about JWT and how they work, so I'll skip this part because I don't want to just paste an entire article.
The benefits of JWT is that you can put data in it (generally informations about your user).
Doing so, you won't have to query your DB to authenticate them and it will result in faster response time for your API / service.
Because you put information into your token (potentially sensible data, or even just mail and name), you must encrypt it so noone except you can read it.
Here comes the secret key : You can think of it as a door key (yes, like in the real world). It allows you to encrypt (close the door) your data so noone can understand it and to decrypt it (open the door) so you can read it.
Since the secret key is on your server and you are the only one that can access it, then you're the only one who can decrypt and read the JWT.
This is just an overview of how it works and I hope it explains well enough the role of the secret key, for more informations and details about JWT, this article is good.
Best regards,
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.