I don't know if this will work out, or is it the right thing to do.
I have created an angularjs application and used firebase to provide my application a "backend", or to contain any data that my application needs.
Also I do not want to bother myself when dealing with authentication, and FirebaseSimpleLogin is just awesome tool for the job.
I could do:
resolve : {
'isAuthenticated': isLoggedIn
}
in my routes so I would be able to prevent them from moving to secured routes. So there is no problem, I already have an authenticated user.
The problem is, i only used firebase to save user data and for auth, and nothing else.
Now I want to do some server tasks in my server, but I want only authenticated users to do that.
How would I determine that the user is authenticated in firebase?
Is this what firebase token generator for.
Or should I just, create an authentication system using nodejs?
Check out the queue pattern. Have the user write items to the queue, have the server respond to them.
The really great part of using Firebase as the API/middle-man is that the worker (i.e. server) does not need to worry about if the client has authenticated. Security rules take care of this.
Just write a rule to only allow logged-in users to write into the queue:
{
"rules": {
"queue": {
"in": {
// I can only write if logged in
".write": "auth !== null",
"user_id": {
// I can only write to the queue as myself, this tells the server which
// out/ queue the user will be listening on
".validate": "auth.uid === newData.val()"
}
},
"out": {
"$userid": {
// I can only listen to my out queue
".read": "auth.uid === $userid"
}
}
}
}
}
Now the user simply writes a record to in/ using push(), then listens on out/ until the server replies.
The server reads records out of the in/ queue, processes them, and writes them back to the out/user_id path.
No RESTful protocols, no express servers, no headaches.
Related
I want to send a json object to another server, independent of my website.
The API I am using requires a user (user x in this case) to log into their service to be authorized so user x can manipulate user x's list. However, other users can't write to x's list. So, users need to request an item to be added to x's list, then a server who is logged into x's account can add it to x's list. Refer to the image below.
http://imgur.com/a/wT53t
I am using node/express.js for the servers on the user's side. However, I don't know what I should use for a server who's only job is to receive requests and write to x's list. Can you provide some guidance as to how I can achieve something like this?
Thanks!
There are two options here:
You have to refresh the list in the realtime for connected users.
To achieve this you should use either: WebSockets(e.g. socket.io) or LongPolling.
In second option you dont have to refresh the list in the realtime. You simply use express. Accept data and refresh the list server-side.
Auth with web sockets:
Once understanding the nature of web sockets, you're free to build any logic around them, including authentication/authorization. The great library doing lots of auth things is passport.js.
Very quick and abstract example of server-side:
socket.on('auth', function(data) {
const vendor = data.vendor,
token = data.id
switch(vendor) {
/*
Here you grab through some social API user social id
and save it to database
*/
}
/* set socket as logged in */
socket.logged = true
/* or even save user object */
socket.user = { vendor, token }
})
Next time you need authorized user, you check:
socket.on('mustBeAuthorized', function() {
if(socket.logged || socket.user) {
/* Continue your logic*/
}
})
I'm trying to implement NodeJS and Socket.io for real time communication between two devices (PC & Smartphones) in my company product.
Basically what I want to achieve is sending a notification to all online users when somebody change something on a file.
All the basic functionality for saving the updates are already there and so, when everything is stored and calculated, I send a POST request to my Node server saying that something changed and he need to notify the users.
The problem now is that when I want to change some code in the NodeJS scripts, as long as I work alone, I can just upload the new files via FTP and just restart the pm2 service, but when my colleagues will start working with me on this story we will have problems merging our changes without overlapping each other.
Launching a local server is also not possible because we need the connection between our current server and the node machine and since our server is online it cannot access our localhosts.
It's there a way for a team to work together in the same Node server but without overlapping each other ?
Implement changes using some other option rather than FTP. For example:
You can use webdav-fs in authenticated or non-authenticated mode:
// Using authentication:
var wfs = require("webdav-fs")(
"http://example.com/webdav/",
"username",
"password"
);
wfs.readdir("/Work", function(err, contents) {
if (!err) {
console.log("Dir contents:", contents);
} else {
console.log("Error:", err.message);
}
});
putFileContents(remotePath, format, data [, options])
Put some data in a remote file at remotePath from a Buffer or String. data is a Buffer or a String. options has a property called format which can be "binary" (default) or "text".
var fs = require("fs");
var imageData = fs.readFileSync("someImage.jpg");
client
.putFileContents("/folder/myImage.jpg", imageData, { format: "binary" })
.catch(function(err) {
console.error(err);
});
And use callbacks to notify your team, or lock the files via the callback.
References
webdav-fs
webdav
lockfile
Choosing Secure Passwords
I'm trying to decide between two methods for inserting a new document to a collection from the client using Meteor.js. Call a Server Method or using the db API directly.
So, I can either access the db api directly on the client:
MyCollection.insert(doc)
Or, I can create a new Server Method (under the /server dir):
Meteor.methods({
createNew: function(doc) {
check(doc, etc)
var id = MyCollection.insert(doc);
return project_id;
}
});
And then call it from the client like this:
Meteor.call('createNew', doc, function(error, result){
// Carry on
});
Both work but as far as I can see from testing, I only benefit from latency compensation (the local cache updating and showing on the screen before the server responds) if I hit the db api directly, not if I use a Server Method, so my preference is for doing things this way. But I also get the impression the most secure approach is to use a Method on the server (mainly because Emily Stark gave it as an example in her video here) but then the db api is available on the client no matter what so why would a Server Method be better?
I've seen both approaches taken when reading source code elsewhere so I'm stumped.
Note. In both cases I have suitable Allow/Deny rules in place:
MyCollection.allow({
insert: function(userId, project){
return isAllowedTo.createDoc(userId, doc);
},
update: function(userId, doc){
return isAllowedTo.editDoc(userId, doc);
},
remove: function(userId, doc){
return isAllowedTo.removeDoc(userId, doc);
}
});
In short: Which is recommended and why?
The problem was that I had the method declarations under the /server folder, so they were not available to the client and this broke latency compensation (where the client creates stubs of these methods to simulate the action but in my case could not because it couldn't see them). After moving them out of this folder I am able to use Server Methods in a clean, safe and latency-compensated manner (even with all my Allow/Deny rules set to false - they do nothing and only apply to direct db api access from the client, not server).
In short: don't use the db api on the client or allow/deny rules on the server, forget they ever existed and just write Server Methods, make sure they're accessible to both client and server, and use these for crud instead.
I'm currently developing an app which needs users and administrators. What I do right now is, I create an admin account on the client with username 'admin' and a default password that should be changed over the accounts-ui.
I do this because creating a user like this:
Accounts.createUser({
username : 'admin',
email : 'test#test.com',
password : 'changethispasswordovertheuserinterface',
profile : { type : 'admin' }
});
doesn't work for me on server side. That means I just create the admin in my client.js and just use this code to check if the admin is logged in.
Template.admin.isAdmin = function () {
var currentUser = Meteor.user();
// Is this hackable?
if (null !== currentUser) {
if ('admin' === currentUser.username) {
return true;
}
}
};
Is this the best way to approach this? And most importantly, is my site hackable like this (Could somebody fake it)?
Yes this is hackable, one could pull up the chrome inspector and modify this quite easily. Or even faster, by typing something like Template.admin.isAdmin = function () { return true; } into Chrome's web console
The best approach would be to only provide the information to the client from the servers end if the user is an admin. So this would mean using Meteor.allow to ensure the database can only be changed by an administrative user, if peforming ops from the client end.
It also depends a bit on what you want to use 'isAdmin' for too. If its content, you could generate the html on the server's end and send it down to the client in a Meteor.methods. At the moment the templating system doesn't provide for locking down the UI on the clients end depending on what the user's document contains.
For any administrative commands, you could use a Meteor.call at which point the user is vetted on the server's and and the transaction is performed there.
The answer on this thread works too AND the top-voted answer has code for a server side, Meteor method call.
Due to the need to do some server side code - mainly sending emails I have decided to use Nodejs & Express for the server side element along with Firebase to hold the data - Partly from a learning experience.
My question is whats the best approach with regards to using the client side Firebase library and the Nodejs library when doing authentication using the Simple Email & Password API. If I do the authentication client side and then subsequently call a different route on the NodeJS side will the authentication for that user be carried across in the request. What would be the approach to test the user is authenticated within Node.
One approach I assume is to get the current users username & password from firebase and then post these to NodeJS and then use the firebase security API on the server to test.
Essentially the problem here is you need to securely convey to your NodeJS server who the client is authenticated as to Firebase. There are several ways you could go about this, but the easiest is probably to have all of your client<->NodeJS communication go through Firebase itself.
So instead of having the client hit a REST endpoint served by your NodeJS server, have the client write to a Firebase location that your NodeJS server is monitoring. Then you can use Firebase Security Rules to validate the data written by the client and your server can trust it.
For example, if you wanted to make it so users could send arbitrary emails through your app (with your NodeJS server taking care of actually sending the emails), you could have a /emails_to_send location with rules something like this:
{
"rules": {
"emails_to_send": {
"$id": {
".write": "!data.exists() && newData.child('from').val() == auth.email",
".validate": "newData.hasChildren(['from', 'to', 'subject', 'body'])"
}
}
}
}
Then in the client you can do:
ref.child('emails_to_send').push({
from: 'my_email#foo.com',
to: 'joe#example.com',
subject: 'hi',
body: 'Hey, how\'s it going?'
});
And in your NodeJS code you could call .auth() with your Firebase Secret (so you can read and write everything) and then do:
ref.child('emails_to_send').on('child_added', function(emailSnap) {
var email = emailSnap.val();
sendEmailHelper(email.from, email.to, email.subject, email.body);
// Remove it now that we've processed it.
emailSnap.ref().remove();
});
This is going to be the easiest as well as the most correct solution. For example, if the user logs out via Firebase, they'll no longer be able to write to Firebase so they'll no longer be able to make your NodeJS server send emails, which is most likely the behavior you'd want. It also means if your server is temporarily down, when you start it back up, it'll "catch up" sending emails and everything will continue to work.
The above seems like a roundabout way of doing things, I would use something like https://www.npmjs.com/package/connect-session-firebase and keep firebase as the model, handling all routes through express. Easier if your express server is rendering templates and not just behaving as a JSON API.
If you are using Firebase Authentication, the client side can import the Firebase Library (e.g. for javascript) and authenticate directly with the library itself
import firebase from 'firebase/app';
const result = await firebase.auth().signInWithEmailAndPassword(_email, _password);
After that, the client can to obtain the ID Token, this token will be informed on each request that will be made to the server (e.g. as header).
const sendingIdToken = await firebase.auth().currentUser.getIdToken();
On the Node.js server side, you can install the Firebase Admin SDK, to verify if the user is authenticated on the Node.js server, like:
// Let's suppose the client informed the token as header
const receivingIdToken = req.headers['auth-token'];
admin.auth().verifyIdToken(receivingIdToken, true)
.then((decodedIdToken) => { /* proceed to send emails, etc */}, (error) => {...});
The Firebase Admin SDK gives full permissions to the Database, so keep the credentials safe.
You should also configure the Security Rules on Firestore (or Firebase Realtime), so the client side can still perform specific operations directly to the database (e.g. listening for realtime changes on a collection), but you can also restrict all access if you want the client to only interact with the node.js server.
For more details, I developed an example of a node.js server that uses the Firestore Database and handles security and more.