express gives error 404 on when trying to visit existing route - node.js

I have created a route to 404.html page if user enters incorrect url route
app.use(function (req, res, next) {
res.status(404).sendFile('public/404.html', {root: __dirname})
})
The problem is that when I enter existing route (in this case I use oauth google authentication) it still leads me to 404 page I created but It should redirect me to google login page.
app.get('/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
Same with logout, it leads me to 404 page
app.get('/logout', (req, res) => {
console.log(`\n`);
console.log('\x1b[1m\x1b[31m', `*** User ${req.user.displayName} has logged out ***`);
req.session = null;
req.logout();
res.redirect('/');
});

Your 404 route needs to be the last route you declare. The declaration order matters. This way, the 404 route handler executes ONLY when no other route has already handled the request (which is what you want it to do).
In Express, routes attempt to match the incoming request in the order the route handlers are registered. Since your 404 handler matches all routes, it has to be last so that it comes into play only when no other route handler has already taken the request.

This is what I always use:
// Pages
app.get('/file', function(req, res){
res.sendFile('/path/to/file.html');
});
// 404
app.get('*', function(req, res){
res.sendFile('/path/to/404/file.html');
res.statusCode = 404;
});
Make sure the 404 handler is after all existing responses, and make sure you restart your server after updating.

Related

Express.js, res.redirect doesn't work after express.static?

I don't know why the redirect from a middleware doesn't work after an express.static.
I want to go to /login when I reload the page /ok. This is my code:
app.use('/ok', express.static('public'));
app.get('/login', function(req, res) {
res.sendFile(path.resolve("public/login.html"));
});
app.use((req, res, next) => {
return res.redirect("/login");
})
If I remove the first line, res.redirect work and the relocation happen on the browser.
If I don't remove the first line, the browser doesn't relocate to /login, but I can see that in the chrome console:
chrome console

Page displays 'null' after authentication

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

Node Express - redirect to login view

I am trying to configure my express application to redirect to a login page based on some logic. I have the following:
app.use('/', function(req, res, next){
if(!req.session.accessToken){
//do something here
}
next();
});
I have a login.html file located in the root of the directory my application is being served from, I am just unsure what I need to call on the res object e.g. redirect, send
Also, I know the above will actually cause an infinite loop.
What's the correct approach here?
You'll want to be careful of your handler order, what you want (if you really want to do this on your own and not use something like Passport) is something like (the somewhat skeleton);
app.use('/login', function(req, res) { // Allows access to login page
res.send('displaying login page'); // before access token check
});
app.use(function(req, res, next) { // Catches access to all other pages
if(!req.session.accessToken) { // requiring a valid access token
res.redirect('/login');
} else {
next();
}
});
// the rest of your routes go here, they should not be called unless authenticated
The most obvious answer is to simply call res.redirect('/login.html'), but that would return a 301 (moved permanently) code to the browser. A more semantically correct solution might be to return a 401 (unauthorized) and render the login.html file to the response.
See Is it possible to send a 401 Unauthorized AND redirect (with a Location)?
So a solution might look something like this:
app.use('/', function(req, res, next){
if(!req.session.accessToken)
res.status(401).sendFile(path.join(__dirname+'/login.html'));
else
next()
});

URL gets changed on browser refresh ($routeProvider is used for client side routing)

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).

Issue with Express and middleware

function redit (req, res, next) {
var session = req.session.user;
if (session) {
res.redirect('/home');
next();
}
else {
res.redirect('/');
next();
}
}
app.get('/', redit, function (req, res){
res.render('home0.ejs');
});
I code this middleware to check if there's a req.session.user, if there is, the user would be redirected to home, if not, would be redirected to /. But when this middleware is called, Chrome says to me Error 310 (net::ERR_TOO_MANY_REDIRECTS)', any solutions...?
You miss the fact that after redirect an anonymous user (with falsy req.session.user value) will end up at the same (/) page - so their identity will be checked up by redir middleware again... and again... and again. Hence the 'TOO MANY REDIRECTS' error.
The common solution is to redirect all the anonymouses to some other gateway page - and that page obviously should NOT check session.user.

Resources