/favicon.ico after login in Node JS - html

I have created a login/register system using express (passport) on my website and I am saving the originalUrl before the user was redirected to the login page but every time after the login, the user is redirected to /favicon.ico instead of the saved Url. Could someone tell me what is the cause of the issue?
My app.use():
app.use((req, res, next) => {
if (!['/login'].includes(req.originalUrl)) {
req.session.returnTo = req.originalUrl;
}
res.locals.currentUser = req.user;
res.locals.success = req.flash('success');
res.locals.error = req.flash('error');
next();
})
My /login get and post request:
app.get('/login', (req, res) => {
res.render('login');
})
app.post('/login', passport.authenticate('local', { failureFlash: true, failureRedirect: '/login' }), (req, res) => {
const redirectUrl = req.session.returnTo || '/';
console.log(redirectUrl);
delete req.session.returnTo;
res.redirect(redirectUrl);
})

You have a race condition in your session between two incoming requests.
Your app.use() middleware is going to see the /favicon.ico request and will overwrite the req.session.returnTo value that your login route may have just set. If these two requests come in one immediately after the other (which is likely when a browser first visits your site), then the /favicon.ico route will mess up the session state you just tried to set with the /login route.
I can't tell what that middleware is trying to do, but it looks like it's very capable of overwriting stuff in the session that other requests are in the middle of using. Redirects after login are much, much safer to do by putting the eventual redirect URL in the query parameter. Then it is stateless on the server and isn't subject to these types of race conditions when there is more than one incoming request to the server form the same user.
FYI, you could also fairly easily prevent this particular problem (though not other potential race conditions) by just putting this route handler before your middleware:
// put this before your middleware
app.get("/favicon.ico", (req, res) => {
res.sendStatus(404);
// or instead of a 404, send an actual favicon.ico file
// just don't let routing continue to your middleware
});
This would keep your middleware from running at all when /favicon.ico is requested and thus prevent that specific place that a race condition with your session data is caused.

Related

Is sending login credentials to server for authentication and authorization in body with content-type: application/json acceptable?

I was looking through multiple stack overflow questions and answers but wasn't able to get anything definitive when it comes to making a request to a server for login authentication and authorization.
My question: Is sending login credentials to server for authentication and authorization in body with content-type: application/json acceptable?
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const [email, password] = formData.values();
fetch('/login', {
method: 'POST',
headers : {'Content-Type' : 'application/json'},
body: JSON.stringify({email, password})
}).then(result =>{ //result is a ReadableStream object
return result.json(); //result.json() parses the data into useable format (json)
}).then(data => {
if(data.isAuthenticated){
handleUserAuthChange(true, ()=>{
history.push('/vehicles');
});
}
}).catch(err => console.log(err));
}
As long as you are using HTTPS, yes. This is a pretty common way of handling login requests
There is a great "tutorial" here on stackoverflow.
Unless the connection is already secure (that is, tunneled through HTTPS using SSL/TLS), your login form values will be sent in cleartext, which allows anyone eavesdropping on the line between browser and web server will be able to read logins as they pass through. This type of wiretapping is done routinely by governments, but in general, we won't address 'owned' wires other than to say this: Just use HTTPS.
In short, you want to always use HTTPS to be sure it's safe.

Using passport.js and plain SQL query to authenticate

I'm working on a project and I have the following issue.
I want to implement logic for user login with Passport API but I'm having difficulties of understanding how it works, especially the way I want to implement it (with plain SQL queries). I have gone thru several tutorials which explain how this can be done ,but the problem is that in them it is shown only with ORMs, and I do not want it that way. I've wrote a few thousand lines of code so far ,but without success which were deleted after this of course and this is the reason I haven't provided any code below.
I'm using MySQL and Express as frameworks to build the website. If you have any brief or advanced idea of how things can happen I will be happy to hear from you.
Thanks in advance !
Passport can be quite confusing at times, I'll give that to you! I'm assuming based on your question that you want to use the "local" login strategy and not offer something like Google or GitHub Single Sign On. I'll also assume you want to use "Sessions" (cookies) rather than something like JWT.
To do this you'll need to first configure passport with your express app up front. This requires you to initialise passport and a session store (you can use MySQL if you like, or something like Redis).
Then you need to configure your "strategy" which in our cases is the local strategy.
I'll run you through an example with some code that shows how this can be done. I'll shove this all into one code snippet but you may wish to break this out into several files.
Snippet you can clone:
https://gist.github.com/BlueHatbRit/5d07d3f98d41d536a776b74fcb843174
Mirrored here for answer longevity:
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
// Create the express app
const app = express();
// Initialise express-session module effectively deals with serilaising some
// form of ID in a cookie which is secured with the given secret. In this case
// express then remembers this ID in memory. When this cookie is handed
// back to your server, express-session takes that ID and matches it up to
// the data it has stored against that ID in memory. Remember, in production
// you will most probably want to hook this up to some sort of data store,
// either Redis, MySQL, etc...
app.use(session({ secret: "cats" }));
// We need some body parser setup to use Passport with express
// you can checkout the body parser and passport docs to find out why
app.use(bodyParser.urlencoded({ extended: false }));
// Now we initialise passport
app.use(passport.initialize());
// Now setup the session strategy, this happens after the express-session
// initialisation as that must run on a request first. Once we have the data
// from express-session (remember, it converted from a session ID given to
// the user via a cookie, back into the data we stored against the ID) we can
// then pull our any additional information.
app.use(passport.session());
passport.serializeUser(function(user, done) {
// This happens at the end of a request, it recieves the
// req.user object, and you can then choose what to serialise
// into the session (returning the user a new cookie with a
// session ID).
// In most cases you'll want to store as little data as possible
// so just a user.id might be fine.
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
// Assume we stored the user ID in the session in the above
// function call, we can now access it.
// You can now take "id" and pass it into your database and
// get back whatever you want in regards to the user. This may
// just be a small representation of the user, or the entire
// record.
// You can use either SQL or an ORM here. The important bit is
// that you call the "done" callback with whatever object you
// want to represent the user.
User.findById(id, function(err, user) {
// In your main request handlers, you will then call `req.user`
// and get back whatever you passed into the callback.
done(err, user);
});
});
// Now we setup the main "login" route, this will do the first round
// of authentication. It will take a username and password, will check
// those credentails and will then decide whether or not to log the user in.
passport.use(new LocalStrategy(function(username, password, done) {
// Run your SQL here to find the user by their username
// Then check their password is correct
// If something fails then call the "done" callback with a descriptive error
// otherwise call "done" with no error, and pass it the "user" object. This will
// be assigned to req.user which will then later be put through our serialize
// function above.
// In this case I'm using an ORM, but you can use something to execute raw SQL
// if you like.
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
// This is a made up function here, you'll need to create this and fill it out
// if you're using SQL you will probably have a function called "validPassword"
// (not assigned to a user object) where you will then pass in the hashed password
// from your database, and the password they provided you (the password string in this
// case).
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
// We have a user and the passwords match so we can return the user object!
return done(null, user);
}
});
// Now we need to mount our configured strategy to an endpoint
app.post('/login', function(req, res, next) {
passport.authenticate('local', {
successRedirect: '/dashboard', // The user logged in fine, redirect them do the dashboard
failureRedirect: '/login', // The login failed, send them back to the login page
// It is possible to use "connect-flash" here to send back the reason but that's outside of the scope of this
});
});
// Now we'll create some middleware to ensure a user is logged in when trying to access
// a protected endpoint
function protected(req, res, next) {
// req.user will only exist if they've been authenticated
if (!req.user) {
return next(new Error('nice try, but you are not logged in!');
}
return next();
}
app.get('/private-things', protected, function(req, res, next) {
// This code will only be accessible if someone goes to /private-things and
// has a valid session!
console.log(the user is logged in!);
console.log(req.user);
res.sendStatus(200);
});
A warning, I have not run this code. All the code is there though you might spot a few syntax errors and will need to write the SQL to match up to your database.

Angular 2: How do I handle redirect routes to my page with incoming JSON data?

I have two problems, I need to be able to redirect users from facebook permissions acceptance from passportjs-facebook and from paypal payments redirect but I don't know how to do this in angular. I need to access posted JSON data coming from my own express server with an angular route which receives and uses that data.
If I do an a href="/auth" login button it sends my user to facebook's page to grant app permissions, after they do it redirects them to /auth/facebook/callback which is a blank white page with this json: {"ok":true,"status":"Login successful","success":true,"token":"...", user: {..}, }. How do I make it so they are redirected back to a page on my angular2 app and that this token is read into a json object within my apps so I can put it in local storage? This is my backend code:
userRouter.get('/auth', passport.authenticate('facebook', {scope: ['public_profile', 'user_friends', 'email']}), (req, res) => {});
userRouter.get('/auth/facebook/callback', function(req,res,next){
passport.authenticate('facebook', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Login failed'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful',
success: true,
token: token
});
});
})(req,res,next);
});
I'd use a res.redirect to the URL of one of your Angular pages, and include the token as a query string.
res.redirect('/#!/myprofile?token=MYTOKEN'); instead of the res.status(200).json... code
Alternatively you can parse the query string sent with the redirect right away in Angular as in this example, but I think that way can be a bit messy. That example will also help you through accessing query strings in Angular2.

Run multiple functions based on a SINGLE form submission (method="post") using Node-express

I am looking to perform multiple actions upon receiving HTML(or EJS) form content using the POST method. I am using Node express, mongoose & mongoDB. Each of the below POST responses work individually but i am unsure how to proceed in updating multiple databases based on ONE SINGLE form submission.
// insert into passport db
app.post('/signup', passport.authenticate('local-signup',
{
successRedirect : '/index', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
//insert into my database here
[the content of in the second function is unimportant as that is working fine and has been stripped down for simplification.]
app.post('/signup', function( req, res )
{
new UserDB(
{
user_id : req.body.content,
first_name : req.body.fname,
}).save( function( err, mySite, count )
{
res.redirect( '/index' );
});
});
I have tried redirecting but the form content is not accessible after the redirect so only the first function stores the data (ie. only 1 database is filled).
How would i run both functions within
app.post('/signup',.....
{
...
});
?
Thanks in advance!
You can do this by making one function the callback of the other. This is easy because each function maintains the same Connect middleware signature, function(req, res, next), where req and res are the request and response objects created and manipulated by the application, and next is the next function to call at the end of the current function's execution.
According to the official documentation, passport.authenticate() is a normal piece of middleware. All you need to do is specify the middleware you want to be called next. Express queues middleware functions in the order in which you pass them into app.post. You can do something like this:
app.post('/signup', passport.authenticate('local-signup', {
failureRedirect : '/signup',
failureFlash : true
}),
function(req, res) {
new UserDB({
user_id : req.body.content,
first_name : req.body.fname,
}).save(function(err, mySite, count) {
res.redirect('/index');
});
});
Middleware is an extremely powerful feature of the Express framework and possibly the single most important one to master. This guide would be a great next step if you want to learn more.

mocha - send json to post express route

I'm trying to send some json data to my '/sign_up' route in mocha test.
request = require 'supertest'
express = require 'express'
app = express()
Authentication = require("#{specDir}/../apps/authentication/routes")
authenticate = new Authentication app
Factory = require "#{specDir}/factories/user"
user = Factory.build 'user'
it 'creates an account', (done) ->
request(app).post('/sign_up').set('Accept', 'application/json').send(user).end (err, res) ->
expect(res.statusCode).to.equal 200
done()
However req.body in the callback function is undefined. Below I've shown a snippet of my route callback
#app.post '/sign_up', (req, res) ->
res.format
html: -> res.status(406).send 'invalid Content-Type'
json: ->
console.log req.body
res.status(200).send status: 'ok'
Probably I'm missing some small detail, but can't see what.. any ideas?
P.S. I'm well aware of that the tests pass and it does what it should, but before I move on to write more tests I gotta know how to send some data.
You're missing a body parser, add app.use(express.json()) in your code somewhere.