I am using Passport-Local (https://github.com/jaredhanson/passport-local) to authenticate with node.js. So far this example works like a charm, since the users are logging in thorugh a post-webform:
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: true }),
function(req, res) {
res.redirect('/');
});
Now, however, I want to code up a JSON-based API to authenticate users by calling a particular URL. Modifying the code block to app.get(… doesn't work though.
Any advice?
I ran into this same problem, and solved it by adding this to my route handler for login:
req.body = req.query;
Maybe not the perfect solution, but it's certainly better than hacking passport. ;)
Also note that there's a pending request in passport-local to fix this problem: https://github.com/jaredhanson/passport-local/pull/12
Maybe https://github.com/yarax/passport-url strategy will be useful for you
It allows to authenticate users with a token giving by GET request
var url = new UrlStrategy({
failRedirect : "/login",
varName : "secret"
}, function (secret, done) { // put your check logic here
if (secret == 'foo') done(null, {id:'bar'});
else done("wrong");
});
passport.use(url);
Related
I am building an application using node.js and express.js with passport authentication using MVC Architecture. I have strictly followed a tutorial on how to implement and integrate passport authentication using a local strategy. It seems like the strategy is working fine. In my controller which is handling the authentication (using passport.authenticate), successRedirect is always executed given that I submit matching details with an instance in the database. However, after redirecting to wherever successRedirect points to, I am getting a GET request Error 500. Afterwards, if I try to access other routes, I still get the same error, thus failing to display the desired view template. However, if I try to access the same routes without attempting to login, the GET request executes successfully with statusCode 200.
The exact error I get is :
GET /dashboard 500 4.313 ms - 941
users.js route
var usersController = require('../../controllers/usersController');
/* POST login */
router.post('/login', usersController.loginAccount);
usersController.js
module.exports.loginAccount = function (req, res, next) {
passport.authenticate('local', {
successRedirect: 'dashboard',
failureRedirect: '/users/login',
failureFlash: true
}) (req, res, next);
}
index.js route
router.get('/dashboard', ensureAuthenticated, indexController.dashboardPage);
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
return next();
else{
req.flash('error_msg', 'Please log in to view this resource');
res.redirect('/users/login');
}
}
Command line after attempting login:
Executing (default): SELECT id, firstname, lastname, email, username, password, address, createdAt, updatedAt FROM clients AS client WHERE client.username = 'nikolaisennn' LIMIT 1;
Serializing user
POST /users/login 302 144.266 ms - 74
Deserializing user
User ID: 65
GET /dashboard 500 4.313 ms - 941
I have been stuck on this issue for a while, tried to find solutions online but I haven't really managed to find what I need. I am sure that there is something small that I am missing, yet I have no clue what it is.
I attempted to login to my application which utilizes the Google OAuth flow. I have successfully logged in to this application in the past by going to
localhost:5000/auth/google
When I select my email, the process just hangs for about a minute and then I get the:
TokenError: Code was already redeemed.
which occurs at localhost:5000/auth/google/callback, which I thought perhaps that would not be a problem because it is a route that is in my authRoutes.js file below:
const passport = require('passport');
module.exports = (app) => {
app.get(
'/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email']
})
);
app.get('/auth/google/callback', passport.authenticate('google'));
app.get('/api/logout', (req, res) => {
req.logout();
// prove to whoever is
// making request that
// they are no longer signed in
res.send(req.user);
});
app.get('/api/current_user', (req, res) => {
res.send(req.user);
});
};
I thought I would check by going to localhost:5000/api/current_user which should be rendering the googleID and _id of the user as an object, but instead I get a blank screen which means I am not successfully logged in.
I am not sure what is going on here.
When you are attempting to go through the Google OAuth flow in your local application and it just hangs, that is not a problem. Your issue was that you did not have your MongoDB database running, so it was difficult for your application to verify if this was a new user or an old user logging in based off whats stored in the database.
I am setting up what I thought would be the simplest auth possibly - a site loads on a log in screen, user enters credentials in a form, on submission I am using Passport.JS and Sequelize to check the credentials. Most all of this is copied from various tutorials, or the Passport website itself.
No matter what I do, change or attempt though, the site just hangs as soon as I click the form submit button. In the dev tools network tab I just shows the post request to /login as pending.
To eliminate all possible added problems, I stripped out Sequelize, and used hard coded users, ala the local use example on the passport github page. Still, no change, to Sequelize was not the problem.
I'm sure it's something dumb. I've tried the obvious solutions, like making sure my form was sending 'username' and 'password'.
My form looks like this:
form(method="post", action="/login")
fieldset
legend Please Log In
label(for="username") Username:
input#username(type='text', name="username", autocomplete="off")
label(for="password") Password:
input#password(type='password', name="password")
button#login(type="submit") Log In
In node my app.js uses a router, which includes this:
var login = require('../app/controllers/login');
app.get('/', login.index);
app.post('/login', login.auth);
The page load ok on the get request. On post it directs to this:
exports.auth = function (req, res, next) {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
});
};
The console.log(req.body) comes up fine, showing the form values, so we are ok to that point. But nothing after. This is the last part:
passport.use(new LocalStrategy(
function(username, password, done) {
console.log('local strat invoked');
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
});
}
));
I swapped out the code that used Sequelize to check the DB for the user with this findByUsername function (copied and pasted straight from the above mentioned post on the passport github page), but as the console.log('local strat invoked') is never coming up, I'm guessing nothing after that point even matters.
Also includes are the passport.serializeUser and passport.deserializeUser, but I cant imagine those are the problem at the stage where I am stuck.
Any idea what step I am missing to get this working?
Passport is middleware, if you embed it in a route handler function, you need to invoke it:
exports.auth = function (req, res, next) {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
})(req, res, next); // <-- NEED TO INVOKE WITH req, res, next
};
or, more simply use it as middleware (which is the recommended approach:
exports.auth = passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
});
I'm using Passport.js to authenticate with Google via OAuth (I'm using the passport-google-oauth strategy). It works fine, but I'm currently redirecting the user to "/", and I'd like to send them to "/" plus the current hash tag. I can send the hash value in a query string parameter, but I can't seem to set that value to the callbackURL property of the object that I'm passing to authenticate.
Can someone provide an example or explanation as to the correct way to do this? I'm not beholden to using the query string, it just seemed the most straight-forward route, but I'm open to using a session variable or something else, if that would be easier or better practice.
Thank you.
You can achieve this effect by storing the return url in the session.
// server
var app, express;
express = require('express');
app = express();
app.configure(function() {
app.use(express.cookieSession({secret: 'shh'}));
});
app.get('/auth/twitter', function(req, res, next) {
// to return to '/#/returnHash', request this url:
// http://example.com/auth/twitter?return_url=%2F%23%2FreturnHash
// on the client you can get the hash value like this:
// encodeURIComponent("/"+window.location.hash)
req.session.return_url = req.query.return_url;
next();
}, passport.authenticate('twitter'));
app.get('/auth/twitter/callback', passport.authenticate('twitter', {
failureRedirect: '/login'
}), function(req, res) {
var url = req.session.return_url;
delete req.session.return_url;
// redirects to /#/returnHash
res.redirect(url);
});
I'm using a passport-local strategy for authenticate users. I followed the guide given by Jared Hanson and installed connect-flash in order to give flash method to the req object. So one of my request handlers is the following:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/'
, failureRedirect: '/login'
, successFlash: 'Bienvenido'
, failureFlash: 'Credenciales no válidas'
})
);
When the user login fails, it redirects the user to /login again but it doesnt flash anything :/
UPDATE:
I use mongodb for session storage and I see this:
> db.sessions.find()
{ "_id" : "qZ2eiTnx6r9LR25JOz/TGhiJ", "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":\"4ffb5b5db9cc16b615000001\"},\"flash\":{\"error\":[\"Credenciales no válidas\"],\"success\":[\"Bienvenido\"]}}" }
So the messages are inserted into the session object but they aren't pulled out. Should I do something special?
I assume you're pulling the messages out and rendering them in a view? Something like:
app.get('/login', function(req, res){
res.render('login', { message: req.flash('error') });
});