Pattern for Using an Access Code with Firebase - ios

I'm currently using Firebase for my app, and I'd like to make parts of my application to not only require user authorization but to also be private and require a user to input an access code to gain entry.
I've already got the authorization piece working with a few different providers and anonymous authentication. My question is, is there a proper pattern already existing for above functionality? Or do I need to write a separate web service to handle this requirement?

If you want to add security to your database you better check this out the Firebase documentation about security rules
In the database console under the Rules you will find the section to add security to your database. Basically it's a JSON object like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
In the example above I just declare that for the complete database to read and write there should be a logged in user.
In the same way I recommend you to read the auth section of the documentation and how to implement it here.
EDITED
Because the example above wasn't clear enough I made another one in my Firebase database. In this example I have a path https://*****.firebaseio.com/users. In the example below you can see that I assigned true to the .read property and auth != null to the .write property, it means that everyone can read this path but only authenticated users can write in this path.
{
"rules": {
"users":{
".read": "true",
".write": "auth != null"
}
}
}
Using the Firebase simulator you can see that read is enable when you are not authenticated.
But if I want to write without authenticate myself I got an error.
Now if I use authentication in the simulator I can perform a write operation.
EDITED VERSION 2 "ACCESS TOKEN"
Ok I see what you mean. I assume you are going to store this "access code" somewhere in your Firebase database. If you want to validate data within the database to allow read or write you can do it as the documentat says here.
{
"rules": {
"users": {
".read": "root.child('access_token').child(auth.uid).exists()"
}
}
}
In the example above I have a path in the database called access_token, in this path I stored a key pair user_uid-accessToken and then using the root property make a query to validate if you have a value for the authenticated user in this path. I'm using the exists() but there are many others methods you can use to make this validation. For example if the access code is hardcoded then you can use the val() method to compare for an exact value.

Related

use variable names in firebase rules

I have an existing firebase project. Every user can save data to a 'folder' with the same name as the userid of the user.
I use the rules like this
"$uid":{
".read":"auth.uid == $uid",
".write":"auth.uid == $uid"
}
But now, the need of collaboration between multiple users has risen.
So, i can't use this rule anymore.
I made a new 'table' in firebase, called 'users' where i can save the users id and the according variable workingDir.
Of course, i would like to keep my database secure, but I don't have a clue to setup the firebase rules for that and use this workingDir variable.
Any help is appreciated

Swift and Firestore security rules, firebase security

I'm new developer working on my first Firestore app. I've changed the rules on Firestore to make the data more secure for user, but it's not allowing read/write.
This is the key line and I don't know how to configure it specific to my app -
match /some_collection/{userId}/{documents=**} {
I don't know if I change the "some_collection" to my collection name or if some_collection in that sense is an actual wildcard type of parameter itself.
Also, do I need to pass in the userID somehow from my swift application to Firestore? where is userID coming from in this line? I'd prefer to make the rule such that only the user who created the data can read/write. I believe this block is to allow any authenticated user, so I'm just trying to explore each step.
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated content owners access
match /some_collection/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid == userId
}
}
}
Addressing your questions:
This is the key line and I don't know how to configure it specific to my app.
match /some_collection/{userId}/{documents=**}
I don't know if I change the "some_collection" to my collection name or if some_collection in that sense is an actual wildcard type of parameter itself.
In the line above "some_collection" is not a firestore wildcard and you need to replace some_collection with the actual value of your collection.
Also, do I need to pass in the userID somehow from my swift application to Firestore?
Yes and it is expected that before reading or writing to/from firestore:
You had already created and configured the firebase object.
firebase.initializeApp({
apiKey: '### FIREBASE API KEY ###',
authDomain: '### FIREBASE AUTH DOMAIN ###',
projectId: '### CLOUD FIRESTORE PROJECT ID ###'
});
You had already authenticated your users with firebase auth.
firebase.auth().signInWithCustomToken(token)
.then((user) => {
// Signed in
// ...
})
.catch((error) => {
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Passing the userId is done by the firebase object when you call db. collection(“col123”).add or any other method. If you look at how firestore is initialized:
var db = firebase.firestore();
You will see its dependency with the firebase object.
where is userID coming from in this line?
The userID is coming from the firebase object.
I believe this block is to allow any authenticated user, so I'm just trying to explore each step.
Yes, the last rules allow any authenticated user to read and write from/to the subcollections/documents wildcard {userId}.
Lastly it is also expected that there is some naming consistency in the ids of your firestore documents or subcollections.
This means when you create firestore documents, use the firebase.auth.uid as the document id.
Otherwise, the rule from above will fail because the value behind {userId} is not equal to firebase.auth.uid of the logged user.
To achieve the latter, you can refer to this answer.
I highly recommend you have a look at this video(from the firebase channel) since it elaborates more on the core concepts of firestore security rules.
I hope you find this useful.

Firebase-Database: deny in general but allow for specific path

I try to generate my Firebase-DB Rules and want to deny writing without Authentication in general and only allow it for a specific path. It gets published correctly but it does not work.
http://myproject.firebaseio.com/test/foo
{
"rules": {
".read": true,
".write": "auth != null",
"foo":{
".write": "true"
}
}
}
UPDATE 1
OK, I found out that Rule-Cascading is making it impossible how I did it above, because
".write": "auth != null"
is preventing me from writing. How can I avoid that
The firebase rules cascade from the top down, so there's no way to block writing at a higher level, but allow it at a lower one. Here's a note right from the docs:
Note: Shallower security rules override rules at deeper paths. Child
rules can only grant additional privileges to what parent nodes have
already declared. They cannot revoke a read or write privilege.
You may need to restructure your data so that the foo object is at the top-level, which would let you have a different write rule on it.
Another option is to simply remove the write rule at the root and add it to any other root-level items that require an authenticated user.

Only writing data to firebase if information doesn't exist - Swift iOS

I want to only update the values email, firstname and lastname if they are blank.
I need this so that if the user decides to change these in the settings, they are not overwritten every time the user logs in with facebook.
Any solutions to check if the fields are blank without a datasnapshot? Trying to maximise efficency.
Current code when user signs in with facebook?
Database Structure for each user:
One way to do this is using a firebase transaction.
A transaction allows you to check the current value of a DB reference before you set/update it. It's main use case is preventing multiple concurrent updates from multiple sources but it can be used for this case as well - read and then write.
In the transaction block you get the value of the DB ref you're transacting on & can check that the value is null (hence 'create' case) -> then update it as required and return TransactionResult.success(withValue: newData).
If the object is already set you simply abort the transaction with TransactionResult.abort() and no write to the DB is executed.
Another option, that doesn't require a read/write, is to set a Firebase database rule on the relevant ref that will only allow write if the previous value was null:
"refPath": {
".write": "data.val() == null && newDataval() != null"
}
Writing a second time to the DB for an existing ref will fail.
I'd go with the transaction - more expressive of the requirement in the client code.
In firebase the only way you have to check if the current value of your fields in your database are empty is to fetch them before you are setting them.
You can check the field is empty only by fetching them.Then Use this code to update a particular value
ref.child("yourKey").child("yourKey").updateChildValues(["email": yourValue])

Firebase rules to access specific child's value

The childByAutoId would be useful if you want to save in a node multiple children of the same type, that way each child will have its own unique identifier.
List:{
KJHBJJHB:{
name:List-1,
owner:John Doe,
user_id:<Fire base generated User_id>
},
KhBHJBJjJ:{
name:List-2,
owner:Jane Lannister,
user_id:<Fire base generated User_id>
},
KhBHJZJjZ:{
name:List-3,
owner:John Doe,
user_id:<Fire base generated User_id>
}
}
I am trying to access the List with the help of the following code:
let ref = FIRDatabase.database().reference(withPath: "/List")
The current user logged into the app is John Doe. When the user accesses the list, I want all the List child whose owner is John Doe(i.e. List-1 & List-3) and ignore the other child values.
Do I have to do this in my application or can this be achieved via Firebase Security rules?
My current rule definition is:
"List":{
".read": "root.child('List/'+root.child('List').val()+'/user_id').val() === auth.uid" }
But this rule is not giving me any success. Any idea how to achieve the desired result?
You're trying to use security rules to filter the list. This is not possible and one of the common pitfalls for developers coming to Firebase from a SQL background. We commonly refer to it as "rules are not filters" and you can learn more about it in:
the Firebase documentation
this answer
our new video series Firebase for SQL developers
and many previous questions mentioning "rules are not filters"
The solution is almost always the same: keep a separate list of the keys of posts that each user has access to.
UserLists:{
JohnUid: {
KJHBJJHB: true,
KhBHJZJjZ: true
},
JaneUid: {
KhBHJBJjJ: true
}
}
This type of list is often referred to as an index, since it contains references to the actual post. You can also find more about this structure in the Firebase documentation on structuring data.

Resources