Users visiting http://localhost/login are instantly redirected to Facebook for confirmation of application usage. Once authorized, Facebook contacts http://localhost/login?code= with a special code that allows the server to obtain the user's information such as their name and gender.
Express().get('/login', Passport().authenticate('facebook', {
failureRedirect: 'http://localhost/',
}), function(req, res) {
database.saveData(req.user, **randomlyGeneratedHash**);
res.cookie('session', **randomlyGeneratedHash**);
res.end();
});
This works as expected, but when authenticated users visit the /login in succession, the whole process is repeated and they get a new cookie.
Is there a way that I can run some code inbetween Express and Passport, to stop Passport from redirecting to Facebook if the user has a valid cookie already?
You can use something similar to ensureAuthenticated on your /login route:
var CheckIfAlreadyLoggedIn = function(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/'); // or where you want them to go
}
next();
};
Express().get('/login', CheckIfAlreadyLoggedIn, Passport().authenticate('facebook', ...));
This would redirect users that are already logged in back to / when they try to access /login.
Related
I have a google auth API in my app, can I somehow attach user data with redirect function? Or how can I see if the user logged in at my react app.
For example here I'm sending username in my request field, but I don't know the way to access it...
router.get('/google/redirect', passport.authenticate('google'), (req, res) => {
res.redirect('http://localhost:3100/login1/' + req.user.username);
});
Thanks in advance!
you have to request the authentication flow alike this:
router.get('/auth/login',
(req, res, next) => {
// Save the url of the user's current page so the app can redirect back to it after authorization
if (req.query.return) {req.session.oauth2return = req.query.return;}
next();
},
// Start OAuth 2 flow using Passport.js
passport.authenticate('google', { scope: ['email', 'profile'] })
);
and then handle the post-back alike this:
// OAuth 2 callback url.
// Use this url to configure your OAuth client in the Google Developers console.
router.get('/auth/google/callback',
// Finish OAuth 2 flow using Passport.js
passport.authenticate('google'), (req, res) => {
// Redirect back to the original page, if any
const redirect = req.session.oauth2return || '/';
delete req.session.oauth2return;
res.redirect(redirect);
}
);
while your localhost does not have any route-able IP, therefore you will never receive any post-back. hosting the script on-line (with a publicly route-able IP) is required to make it work "as expected".
I'm creating a simple PWA to draw in multiple data sources into one application. I'm currently trying to set up authentication using a combination of passport and the twitter-strategy.
After the user has successfully authenticated they're account, twitter redirects to the callback endpoint, with the valid user data.... essentially the auth has been successful. However, when sending the user back to the client side application a html document with the word null is presented, rather than the application.
With the following code, I expect:
Twitter to return to callback URL
Server to perform actions in authSuccess function
Redirect to the provided url on the client
routes.js to server the application shell via the catch all route
Client application to boot and handle the URL served
Currently, only the first two steps are successful, and the app simply displays null (with the correct url in the address bar), rather than the expected output. Changing the location of the writeHead() call to / works, and the user is authenticated as expected ().
routes.js
let users = require('../controllers/userController');
app.get('/user/auth/twitter/callback',
passport.authenticate('twitter', {
failWithError: true
}),
function(req, res) {
console.log('[Twitter] Auth success route hit');
users.authSuccess(req, res);
},
function(err, req, res, next) {
console.log('[Twitter] Auth failure route hit');
users.authFailure(err, req, res, next);
}
);
app.get('*', function(req, res){
console.log('[Route] Catch All: ' + req.path);
res.sendFile(path.resolve(__dirname, '../../public/index.html'));
});
userController.js
authSuccess(req, res) {
console.log('[User Controller] User',req.user);
// Set some cookies here
res.writeHead(302, {'Location': '/user/profile'});
// res.redirect('/user/profile');
res.end();
}
Any help much appreciated. If you need more code, just ask :)
Thanks
I have my Express app setup using Passport for authorization. When a new user signs up, I want to do an email verification. So, after the user posts credentials, the /signup route gets the request and with success redirects to /sendmail for verification.
app.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/sendmail',
failureRedirect : '/signup'
}));
Also, to prevent unauthorized session, within the /signup route, the user is logged out and the session is destroyed.
app.get('/sendmail', function(req, res) {
res.render('mailsent.ejs', {
message: 'An email with verification link has been sent to ' + req.user.email + '. Please follow the link in your mail to verify your account before logging in.'
});
/* From keeping user authenticated after signup (not verfied yet)*/
req.logOut();
req.session.destroy();
}
});
My question is, as the session is already destroyed, browser gets nothing back when the end-user refreshes the browser, or directly accesses the /sendmail route. How to prevent this. In other words, in the app.get('/sendmail') route, how would I check if the session is on(valid req object) else redirect to '/'.
You can either use a middleware route like so:
app.use('/sendmail', function(req, res, next) { // Middleware for only the `/sendmail` route
if (req.session.authenticated) {
next();
} else {
res.redirect("/");
}
});
Or just put it right into your route:
app.get('/sendmail', function(req, res) {
if (!req.session.authenticated) {
return res.redirect("/"); // Redirect to home page if not authenticated
}
res.render('mailsent.ejs', {
message: 'An email with verification link has been sent to ' + req.user.email + '. Please follow the link in your mail to verify your account before logging in.'
});
/* From keeping user authenticated after signup (not verfied yet)*/
req.logOut();
req.session.destroy();
}
});
I have a problem with sessions in my app. I'm trying to learn Passport.js based on this tutorial: http://www.sitepoint.com/local-authentication-using-passport-node-js/ . What I want to do is to allow the acccess for only authenticated users. The process of login works great, but when I check if the user is authenticated, it always says not. What could go wrong?
Here is the checking function:
if (req.isAuthenticated()) {
return next();
else {
res.redirect('/');
}
Here is the path from the router:
router.get('/secret', isAuthenticated, function(req, res) {
res.send('Welcome to the secret page');
});
I didn't find any domunentation about how to check if the session was established, where it is and so on.
Try this, taken from passport.js documentation.
app.get('/secret', passport.authenticate('local'), function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
});
http://passportjs.org/guide/authenticate/
I am using Angular for client and Nodejs (Express) for server side to build single page application. To support browser history for different view, I am using $routeProvider. It works well if I don't refresh the browser. But whenever I refresh the browser I notice that URL is changed which caused issue as that URL pattern doesn't exist at server. Following are more details.
Angular js router code:
$routeProvider.
when('/categoryview', {
templateUrl: 'templates/partials/app/categoryview/CategoryView.html',
controller: 'ApplicationController'
}).
when('/:categoryId/themes', {
templateUrl: 'templates/partials/app/themeview/ThemeView.html',
controller: 'ThemeViewController'
})
.otherwise({redirectTo: '/categoryview'});
URL in browser as application launched first time: http://localhost:3000/themelibrary#/categoryview
URL in browser on refresh: http://localhost:3000/categoryview#/categoryview
If you notice then you will found that the root URL "/themelibrary" is changed into "/categoryview" which caused issue as "/categoryview" is not supported by server. I also tried different version of Angularjs but not success.
Please help and let me know if need more code to explain this problem.
Edit: Added Nodejs router details
UI Routes:
module.exports = function(app, passport) {
// route for home page
app.get('/', function(req, res) {
res.redirect('/login');
});
//Route for login to present the login page back to user
app.get('/login', function(req, res) {
res.set({'content-type': 'text/html; charset=utf-8'})
res.render('login.ejs', {message: req.flash('loginMessage')})
});
//Route to get the username and password and authenticate
app.post('/authenticate', passport.authenticate('local-login', {
successRedirect: '/themelibrary', // redirect to the secure themelibrary section
failureRedirect: '/login', // redirect back to the signup page if there is an error
failureFlash: true // allow flash messages
}));
// route for default lending page
app.get('/themelibrary', isLoggedIn, function(req, res) {
var url= require('url');
console.log("themelibrary hash url >> " + url.hash);
res.charset = 'utf8';
res.set({'content-type': 'text/html; charset=utf-8'})
res.render('index.ejs', {
user: req.user
// get the user out of session and pass to template
});
});
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
API Routes:
module.exports = function(app) {
app.get('/users/:id', userService.getUserById);
app.get('/users', userService.getAllUsers);
app.post('/themes', themeService.addTheme);
app.get('/themes/:id', themeService.getThemeById);
app.put('/themes/:id', themeService.updateTheme);
app.delete('/themes/:id', themeService.deleteTheme);
app.get('/themes', themeService.getThemes);
app.get('/resources/:code', languageResourceService.getLanguageResourceByCode);
app.get('/config', applicationConfigService.getApplicationConfig);
app.post('/keepalive', applicationConfigService.keepAlive);
app.get('/categories', categoryService.getAllCategories);
};
I would need to see your express routing rules to give a full answer, but since themelibrary is not a valid route according to the $routeProvider, your otherwise rule is being activated if you browse to this from within your application.
If you refresh the browser at this URL, $routeProvider is bypassed and the request is sent directly to your node.js instance where express will handle the route.
As for the hash route, that all depends if you have html5mode enabled or not as #david-spence pointed out.
Edit
The penny finally dropped on this one. If your angular app has loaded (and the only way for it to load is via the /themelibrary path), it will take over all of your routing, so any route changes via the application will be handled by ngRoute. That is to say, there will be no page reloads. Therefore, if the backend server is being hit by a request to /categoryview, some other part of the application is requesting a full page redirect via window.location.href or something similar.
In short, your routes are fine, some other part of the application is bypassing your routes and going straight back to the server (which it shouldn't).