Detecting if someone is logged into Meteor from a regular Node.js application - express

Is there a way for me to check to see if someone is logged into Meteor from outside of Meteor; for example, from an Express.js application? I would like to know from the Express app who the currently logged in user is on a particular client so that if the API were called, we would know who to apply the results of the API call to.

So this is best done it two parts.
A method to check whether the user is online in meteor
You can probably do it with a meteor smart package (community package repo) : https://github.com/erundook/meteor-profile-online
Make sure you have meteorite, installed via npm install meteorite -g
In your package repo use : mrt add profile-online
Accessing meteor's data using Express
To access the stuff in Express you would need a DDP client, I know this one works with pre1 (The version of DDP with Meteor 0.57+): https://github.com/EventedMind/node-ddp-client
You can have a method that checks for you in meteor
Server js (Meteor)
Meteor.methods({
'isonline: function(id) {
return Meteor.users.find(id).profile.online;
}
}
Express:
var client = new DDPClient({
host: "localhost",
port: 3000
});
userid = '1' //The user _id of the person you want to check
client.connect(function () {
console.log("Connected to Meteor at localhost:3000");
client.call("isonline", [userid], function(err,result) {
client.close();
if(!err) {
if(result) {
console.log("User " + userid + " is online");
}
else
{
console.log("That user isn't online");
}
}
else
{
console.log(err)
}
});
});

Related

Using Express Middleware in Actions on Google

As mentioned in other newbie question (Google Assistant - Account linking with Google Sign-In) I have an Express app which supports Google authentication and authorization via Passport and now with the help of #prisoner my Google Action (which runs off the same Express app) supports Google login in this way https://developers.google.com/actions/identity/google-sign-in.
My question now is how can I use the varous middlewares that my Express app has as part of the Google Assistant intent fullfillments? A couple of examples:
1) I have an intent
// Handle the Dialogflow intent named 'ask_for_sign_in_confirmation'.
gapp.intent('Get Signin', (conv, params, signin) => {
if (signin.status !== 'OK') {
return conv.ask('You need to sign in before using the app.');
}
const payload = conv.user.profile.payload
console.log(payload);
conv.ask(`I got your account details, ${payload.name}. What do you want to do next?`)
});
Now just because the user is signed in to Google in my action presumably doesn't mean that they have authenticated (via the Google Passport strategy) into my Express app generally? However from the above I do have access to payload.email which would enable me to use my site Google login function
passportGoogle.authenticate('google',
{ scope: ['profile', 'email'] }));'
which essentially uses Mongoose to look for a user with the same details
User.findOne({ 'google.id': profile.id }, function(err, user) {
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user);
....
ok, I would need to modify it to check the value of payload.email against google.email in my DB. But how do I associate this functionality from the Express app into the intent fullfillment?
2) Given the above Get Signin intent how could I exectute an Express middleware just to console.log('hello world') for now? For example:
gapp.intent('Get Signin', (conv, params, signin) => {
if (signin.status !== 'OK') {
return conv.ask('You need to sign in before using the app.');
}
authController.assistantTest;
const payload = conv.user.profile.payload
console.log(payload);
conv.ask(`I got your account details, ${payload.name}. What do you want to do next?`)
});
Here authController.assistantTest; is
exports.assistantTest = (req, res) => {
console.log('hello world');
};
Any help / links to docs really appreciated!
It looks like you're trying to add a piece of functionality that runs before your intent handler. In your case, it's comparing user's email obtained via Sign In versus what's stored in your database.
This is a good use case for a middleware from Node.js client library (scroll down to "Scaling with plugins and middleware
" section). The middleware layer consists of a function you define that the client library automatically runs before the IntentHandler. Using a middleware layer lets you modify the Conversation instance and add additional functionality.
Applying this to your example gives:
gapp.middleware(conv => {
// will print hello world before running the intent handler
console.log('hello world');
});
gapp.intent('Get Signin', (conv, params, signin) => {
if (signin.status !== 'OK') {
return conv.ask('You need to sign in before using the app.');
}
authController.assistantTest;
const payload = conv.user.profile.payload
console.log(payload);
conv.ask(`I got your account details, ${payload.name}. What do you want to do next?`)
});
You could perform the authentication logic in the middleware, and potentially utilize conv.data by keeping track if user's email matched records from your database.

react-native: notify server that user logged into Facebook oAuth

So this is probably a thing I am missing.... I am building a react-native app for IOS, using facebook SDK for Facebook login (react-native-fbsdk).
it all works fine.... but, I want the app to access my server, and my server needs to know that the user is logged in (and who the user is).
I know how to do it with the standard oAuth server flow, but how do I do it in this case? how do I even get the code or access token?
In the FB documentation all I see is how to make requests from the app to FB API, I didn't find where to have a callback on the server, so that I can setup the session cookie with user info.
Thanks!
Use the LoginButton and set the required permissions. It will return you the access token, that you can send to your server. The server gets the username, email etc. via this access token from the facebook oauth service. Then the server can open the session and send the session id back to your react native app.
<LoginButton
readPermissions={["email", "public_profile"]}
onLoginFinished={
(error, result) => {
if (error) {
//alert("login has error: " + result.error);
} else if (result.isCancelled) {
// cancelled
} else {
AccessToken.getCurrentAccessToken().then(
(data) => {
console.log("acces token:", data);
const token = data.accessToken.toString();
// call your server
// server can get user info from facebook
// returns back the session id
}
)
}
}
}
onLogoutFinished={() => true}/>

Creating a non-oauth Meteor Accounts package

The accounts-foobar packages all rely on oauth-based authentication systems, and involve quite a bit of confusing, undocumented boilerplate. I'm wondering if there's an easy way to create a package for a non-oauth authentication system that will integrate normally with the Meteor accounts system. The non-oauth system I have in mind is a simple external API that just accepts a username and password, and returns a simple json object with success data or an error.
Is there a simple way to do this? Does Meteor provide an API for this that I've missed?
EDIT: This bit works fine, I'm just not entirely sure how to hook this up to the accounts system:
HTTP.post('https://my-site.com/api/login.json', { params: { username: 'foo', password: 'bar' } }, function (error, result) {
if (result) console.log('User data:', result.data);
});
// User data: { userId: 217, username: "foobar" }
It looks like Meteor's accounts-password packages should work for you (simple username/password based auth), however if you need something custom you can do it yourself.
You can roll your own auth package if you don't want to use any of the built in accounts-* packages. You simply need to register your own login handler and do a little bit of bookkeeping to keep the sessions authenticated on reconnects.
Step by step:
1: Add accounts-base package: meteor add accounts-base
2: On the server, add a Accounts.registerLoginHandler call
Accounts.registerLoginHandler(function(loginRequest) {
// ... check loginRequest for proper credentials - up to you
var userId = something; // determined by the credentials check
// add a resume token so that Meteor can resume your session on reconnect
var stampedToken = Accounts._generateStampedLoginToken();
Meteor.users.update(session.user,
{$push: {'services.resume.loginTokens': stampedToken}});
return {
id: userId,
token: stampedToken.token
});
3: Call login on the client
var loginRequest = { ... your auth credentials ... };
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (!err) { ... do stuff here on successful login ... }
}});
That's it!

Communication between AngularJS and a Jersey Webservice which are on a different domain. Can't access correct session

Lately I've been playing around with AngularJS and Java EE 6. I've build an webservice with Jersey and deployed the project on Glassfish. Because I needed some kind of authentication and an OAuth implementation or an JDBCRealm seemed overkill I decided to just create a session if the user successfully logged in.
#POST
#Path("/login")
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
public Response login(LoginDAO loginData, #Context HttpServletRequest req) {
req.getSession().invalidate();
loginData.setPassword(PasswordGenerator.hash(loginData.getPassword()));
User foundUser = database.login(loginData);
if(foundUser == null) {
return Response.status(Status.CONFLICT).build();
}
req.getSession(true).setAttribute("username", foundUser.getUsername());
return Response.ok().build();
}
#GET
#Path("/ping")
public Response ping(#Context HttpServletRequest req) {
if(req.getSession().getAttribute("username") == null) {
return Response.ok("no session with an username attribute has been set").build();
}
return Response.ok(req.getSession(true).getAttribute("username")).build();
}
This seems to work alright, if I post to /login from Postman or from a basic jQuery webpage deployed on glassfish I do get the correct username back and a session has been placed. If I then send a GET request to /ping I do get the username back from which I logged in.
I've an AngularJS application deployed on a node.js webserver which needed to login. Because this server is on another port its on another domain and I had to go through the pain of enabling cors. I did this by building a container response filter which sets the response headers.
public class CrossOriginResourceSharingFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest creq, ContainerResponse cresp) {
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Origin", "http://localhost:8000");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Credentials", "true");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
cresp.getHttpHeaders().putSingle("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
return cresp;
}
}
This did made it possible for me to send different types of HTTP requests from AngularJS to Java EE 6 application deployed on glassfish.
The problem is that when I send a POST request from AngularJS to the /login method, a session is created and I do get my username back. But when I send a GET request to the /ping method I get the "no session with an username attribute has been set" notice.
I believe this has to do with cross domain prevention and that I've to set the withCredentials tag when I send a xhr request. I've been trying to do this in AngularJS but haven't found out how to do this.
function LoginCtrl($scope, $http) {
$scope.login = function() {
$http.post("glassfish:otherport/api/login", $scope.credentials).
success(function(data) {
console.log(data);
}).
error(function(data, error) {
console.log(error);
});
};
};
And in another controller:
$scope.getUsername = function() {
$http.get("glassfish:otherport/api/ping", {}).
success(function(data) {
$scope.username = data;
}).
error(function() {
$scope.username = "error";
})
}
I've tried to set withCredentials is true
$http.defaults.withCredentials = true;
This however didn't solve my problem. I also tried to send it with every request in the config parameter but this didn't solve my problem either.
Depending on the version of AngularJS you are using you might have to set it on each $http.
Since 1.2 you can do:
$http.get(url,{ withCredentials: true, ...})
From 1.1.1 you can globally configure it:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
If you're using an older version of Angular, try passing a config object to $http that specifies withCredentials. That should work in versions before 1.1:
$http({withCredentials: true, ...}).get(...)
See also mruelans answer and:
https://github.com/angular/angular.js/pull/1209
http://docs.angularjs.org/api/ng.$http
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#section_5
just an update to #iwein anwser, that we can now set in config itself
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}]).
https://github.com/angular/angular.js/pull/1209
(available only after unstable version: 1.1.1)
In 1.2 version, this doesn't work for me:
$http({withCredentials: true, ...}).get(...)
if I read the doc, the shortcut method should take the config object
$http.get(url,{ withCredentials: true, ...})
$http is a singleton, That's the only way to mix in a same application requests with and without credentials.

user authentication libraries for node.js?

Are there any existing user authentication libraries for node.js? In particular I'm looking for something that can do password authentication for a user (using a custom backend auth DB), and associate that user with a session.
Before I wrote an auth library, I figured I would see if folks knew of existing libraries. Couldn't find anything obvious via a google search.
-Shreyas
If you are looking for an authentication framework for Connect or Express, Passport is worth investigating: https://github.com/jaredhanson/passport
(Disclosure: I'm the developer of Passport)
I developed Passport after investigating both connect-auth and everyauth. While they are both great modules, they didn't suit my needs. I wanted something that was more light-weight and unobtrusive.
Passport is broken down into separate modules, so you can choose to use only what you need (OAuth, only if necessary). Passport also does not mount any routes in your application, giving you the flexibility to decide when and where you want authentication, and hooks to control what happens when authentication succeeds or fails.
For example, here is the two-step process to setup form-based (username and password) authentication:
passport.use(new LocalStrategy(
function(username, password, done) {
// Find the user from your DB (MongoDB, CouchDB, other...)
User.findOne({ username: username, password: password }, function (err, user) {
done(err, user);
});
}
));
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
// Authentication successful. Redirect home.
res.redirect('/');
});
Additional strategies are available for authentication via Facebook, Twitter, etc. Custom strategies can be plugged-in, if necessary.
Session + If
I guess the reason that you haven't found many good libraries is that using a library for authentication is mostly over engineered.
What you are looking for is just a session-binder :) A session with:
if login and user == xxx and pwd == xxx
then store an authenticated=true into the session
if logout destroy session
thats it.
I disagree with your conclusion that the connect-auth plugin is the way to go.
I'm using also connect but I do not use connect-auth for two reasons:
IMHO breaks connect-auth the very powerful and easy to read onion-ring architecture of connect. A no-go - my opinion :).
You can find a very good and short article about how connect works and the onion ring idea here.
If you - as written - just want to use a basic or http login with database or file. Connect-auth is way too big. It's more for stuff like OAuth 1.0, OAuth 2.0 & Co
A very simple authentication with connect
(It's complete. Just execute it for testing but if you want to use it in production, make sure to use https)
(And to be REST-Principle-Compliant you should use a POST-Request instead of a GET-Request b/c you change a state :)
var connect = require('connect');
var urlparser = require('url');
var authCheck = function (req, res, next) {
url = req.urlp = urlparser.parse(req.url, true);
// ####
// Logout
if ( url.pathname == "/logout" ) {
req.session.destroy();
}
// ####
// Is User already validated?
if (req.session && req.session.auth == true) {
next(); // stop here and pass to the next onion ring of connect
return;
}
// ########
// Auth - Replace this example with your Database, Auth-File or other things
// If Database, you need a Async callback...
if ( url.pathname == "/login" &&
url.query.name == "max" &&
url.query.pwd == "herewego" ) {
req.session.auth = true;
next();
return;
}
// ####
// This user is not authorized. Stop talking to him.
res.writeHead(403);
res.end('Sorry you are not authorized.\n\nFor a login use: /login?name=max&pwd=herewego');
return;
}
var helloWorldContent = function (req, res, next) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('authorized. Walk around :) or use /logout to leave\n\nYou are currently at '+req.urlp.pathname);
}
var server = connect.createServer(
connect.logger({ format: ':method :url' }),
connect.cookieParser(),
connect.session({ secret: 'foobar' }),
connect.bodyParser(),
authCheck,
helloWorldContent
);
server.listen(3000);
NOTE
I wrote this statement over a year ago and have currently no active node projects. So there are may be API-Changes in Express. Please add a comment if I should change anything.
Looks like the connect-auth plugin to the connect middleware is exactly what I need
I'm using express [ http://expressjs.com ] so the connect plugin fits in very nicely since express is subclassed (ok - prototyped) from connect
I was basically looking for the same thing. Specifically, I wanted the following:
To use express.js, which wraps Connect's middleware capability
"Form based" authentication
Granular control over which routes are authenticated
A database back-end for users/passwords
Use sessions
What I ended up doing was creating my own middleware function check_auth that I pass as an argument to each route I want authenticated. check_auth merely checks the session and if the user is not logged in, then redirects them to the login page, like so:
function check_auth(req, res, next) {
// if the user isn't logged in, redirect them to a login page
if(!req.session.login) {
res.redirect("/login");
return; // the buck stops here... we do not call next(), because
// we don't want to proceed; instead we want to show a login page
}
// the user is logged in, so call next()
next();
}
Then for each route, I ensure this function is passed as middleware. For example:
app.get('/tasks', check_auth, function(req, res) {
// snip
});
Finally, we need to actually handle the login process. This is straightforward:
app.get('/login', function(req, res) {
res.render("login", {layout:false});
});
app.post('/login', function(req, res) {
// here, I'm using mongoose.js to search for the user in mongodb
var user_query = UserModel.findOne({email:req.body.email}, function(err, user){
if(err) {
res.render("login", {layout:false, locals:{ error:err } });
return;
}
if(!user || user.password != req.body.password) {
res.render("login",
{layout:false,
locals:{ error:"Invalid login!", email:req.body.email }
}
);
} else {
// successful login; store the session info
req.session.login = req.body.email;
res.redirect("/");
}
});
});
At any rate, this approach was mostly designed to be flexible and simple. I'm sure there are numerous ways to improve it. If you have any, I'd very much like your feedback.
EDIT: This is a simplified example. In a production system, you'd never want to store & compare passwords in plain text. As a commenter points out, there are libs that can help manage password security.
Also have a look at everyauth if you want third party/social network login integration.
Here is some code for basic authentication from one of my projects. I use it against CouchDB with and additional auth data cache, but I stripped that code.
Wrap an authentication method around you request handling, and provide a second callback for unsuccessfull authentication. The success callback will get the username as an additional parameter. Don't forget to correctly handle requests with wrong or missing credentials in the failure callback:
/**
* Authenticate a request against this authentication instance.
*
* #param request
* #param failureCallback
* #param successCallback
* #return
*/
Auth.prototype.authenticate = function(request, failureCallback, successCallback)
{
var requestUsername = "";
var requestPassword = "";
if (!request.headers['authorization'])
{
failureCallback();
}
else
{
var auth = this._decodeBase64(request.headers['authorization']);
if (auth)
{
requestUsername = auth.username;
requestPassword = auth.password;
}
else
{
failureCallback();
}
}
//TODO: Query your database (don't forget to do so async)
db.query( function(result)
{
if (result.username == requestUsername && result.password == requestPassword)
{
successCallback(requestUsername);
}
else
{
failureCallback();
}
});
};
/**
* Internal method for extracting username and password out of a Basic
* Authentication header field.
*
* #param headerValue
* #return
*/
Auth.prototype._decodeBase64 = function(headerValue)
{
var value;
if (value = headerValue.match("^Basic\\s([A-Za-z0-9+/=]+)$"))
{
var auth = (new Buffer(value[1] || "", "base64")).toString("ascii");
return {
username : auth.slice(0, auth.indexOf(':')),
password : auth.slice(auth.indexOf(':') + 1, auth.length)
};
}
else
{
return null;
}
};
A few years have passed and I'd like to introduce my authentication solution for Express. It's called Lockit. You can find the project on GitHub and a short intro at my blog.
So what are the differences to the existing solutions?
easy to use: set up your DB, npm install, require('lockit'), lockit(app), done
routes already built-in (/signup, /login, /forgot-password, etc.)
views already built-in (based on Bootstrap but you can easily use your own views)
it supports JSON communication for your AngularJS / Ember.js single page apps
it does NOT support OAuth and OpenID. Only username and password.
it works with several databases (CouchDB, MongoDB, SQL) out of the box
it has tests (I couldn't find any tests for Drywall)
it is actively maintained (compared to everyauth)
email verification and forgot password process (send email with token, not supported by Passport)
modularity: use only what you need
flexibility: customize all the things
Take a look at the examples.
A different take on authentication is Passwordless, a token-based authentication module for express that circumvents the inherent problem of passwords [1]. It's fast to implement, doesn't require too many forms, and offers better security for the average user (full disclosure: I'm the author).
[1]: Passwords are Obsolete
A word of caution regarding handrolled approaches:
I'm disappointed to see that some of the suggested code examples in this post do not protect against such fundamental authentication vulnerabilities such as session fixation or timing attacks.
Contrary to several suggestions here, authentication is not simple and handrolling a solution is not always trivial. I would recommend passportjs and bcrypt.
If you do decide to handroll a solution however, have a look at the express js provided example for inspiration.
Good luck.
There is a project called Drywall that implements a user login system with Passport and also has a user management admin panel. If you're looking for a fully-featured user authentication and management system similar to something like what Django has but for Node.js, this is it. I found it to be a really good starting point for building a node app that required a user authentication and management system. See Jared Hanson's answer for information on how Passport works.
Here are two popular Github libraries for node js authentication:
https://github.com/jaredhanson/passport ( suggestible )
https://nodejsmodules.org/pkg/everyauth
Quick simple example using mongo, for an API that provides user auth for ie Angular client
in app.js
var express = require('express');
var MongoStore = require('connect-mongo')(express);
// ...
app.use(express.cookieParser());
// obviously change db settings to suit
app.use(express.session({
secret: 'blah1234',
store: new MongoStore({
db: 'dbname',
host: 'localhost',
port: 27017
})
}));
app.use(app.router);
for your route something like this:
// (mongo connection stuff)
exports.login = function(req, res) {
var email = req.body.email;
// use bcrypt in production for password hashing
var password = req.body.password;
db.collection('users', function(err, collection) {
collection.findOne({'email': email, 'password': password}, function(err, user) {
if (err) {
res.send(500);
} else {
if(user !== null) {
req.session.user = user;
res.send(200);
} else {
res.send(401);
}
}
});
});
};
Then in your routes that require auth you can just check for the user session:
if (!req.session.user) {
res.send(403);
}
Here is a new authentication library that uses timestamped tokens. The tokens can be emailed or texted to users without the need to store them in a database. It can be used for passwordless authentication or for two-factor authentication.
https://github.com/vote539/easy-no-password
Disclosure: I am the developer of this library.
If you need authentication with SSO (Single Sign On) with Microsoft Windows user account. You may give a try to https://github.com/jlguenego/node-expose-sspi.
It will give you a req.sso object which contains all client user information (login, display name, sid, groups).
const express = require("express");
const { sso, sspi } = require("node-expose-sspi");
sso.config.debug = false;
const app = express();
app.use(sso.auth());
app.use((req, res, next) => {
res.json({
sso: req.sso
});
});
app.listen(3000, () => console.log("Server started on port 3000"));
Disclaimer: I am the author of node-expose-sspi.
slim-auth
A lightweight, zero-configuration user authentication module. It doesn't need a sperate database.
https://www.npmjs.com/package/slimauth
It's simple as:
app.get('/private-page', (req, res) => {
if (req.user.isAuthorized) {
// user is logged in! send the requested page
// you can access req.user.email
}
else {
// user not logged in. redirect to login page
}
})