Can I alert the user from the route/middleware? - javascript

I am using the route to check if a token is valid or not. If it isn't I route the user to the log in page. I want to let the users know they're being logged out either as an alert or on the page.
What happens is a user clicks on Link A (to take them to another page on the website), the route calls a validate.js file:
route.js
var checkToken = require('../validate.js');
router.use(checkToken.checkToken);
This then calls the validate.js file which makes a HTTP call to check
if the token is valid, if it isn't it redirects the user to the Login
page:
validate.js
var checkToken = function(req, res, next) {
if (config.enableTokenValidation) {
var usersToken = req.user.token;
validateToken(receivedToken, req.requestId, function(err, response, body) {
if (err || response.statusCode != 200) {
console.log("Error, token is not valid");
res.redirect("/auth/logout/");
} else {
return next();
}
});
How can I send a message to the loginView.js file so that I can display the error in the front end (or create an alert)?
But as this happens in the middleware and it is other routes to other pages within the program that trigger the validation check, the login page doesn't make the check and therefore I can't get the response there to alert the user.
If there any way of achieving this using the way I'm going about it, or are there any other ways I can go about it?
Many Thanks

Instead of doing
res.redirect();
Why do not you send an error message like
res.status('401').send({error:'Invalid Token'});
Then you can take the necessary steps in the errorHandler() of the api call.

You can return an object that contains a method that fires an Alert message (or a change in your HTML, if you want to change the view). Then you use yourObject.method from the Frontend.

Related

Express js middleware is not working as expected. It is showing too many redirections

Express js middleware is not working as expected. It is showing too many redirections.
When i remove the token or logout it shows in the browser that too many redirections
Middleware
const isAuthenticate = async (req, res, next) => {
const token = req.cookies.jwt;
if (token) {
jwt.verify(token, "thisisjwtsecret", async (err, token_decode) => {
if (!err) {
const u_id = token_decode._id;
const userData = await User.findOne({ _id: u_id });
req.user = userData;
req.isAuth = true;
next();
} else {
res.redirect("/user/login");
}
});
} else {
res.redirect("/user/login");
}
};
Route.js
// Auth Controller
const AuthController = require("../../controllers/auth/AuthController");
const { isAuthenticate } = require("../../middlewares/isAutheticated");
router.get("/user/login", isAuthenticate, AuthController.login);
router.post("/user/login", AuthController.checkLogin);
router.get("/user/register", isAuthenticate, AuthController.createUser);
router.post("/user/register", isAuthenticate, AuthController.storeUser);
module.exports = router;
LOgin function
// Showing Login Page to User
const login = (req, res) => {
return res.render("auth/login");
};
When i remove the token or logout it shows in the browser that too many redirections
Now that you've shown revised code for isAuthenticate(), the redirect loop is caused by the redirects in that code. Here's what happens:
Some route you have (any route) that uses isAuthenticate as middleware for the route detects that the user is not logged in. It then redirects to /user/login. That's fine up to that point. Then, the browser issues a new request for /user/login and that takes you to this route definition:
router.get("/user/login", isAuthenticate, AuthController.login);
But, that route definition again runs the isAuthenticate() middleware which redirects to /user/login and thus you have an infinite redirect loop.
Probably you just need to remove the isAuthenticate() check from this route. If the user is already going to the /user/login page, you don't need to check their authentication or redirect them. If you have a reason to want to know if they are authenticated or not, then you need a separate version that ONLY does the auth check and does not redirect and you can use that in the /user/login route definition.
Original answer before code was shown that did res.redirect().
So, this middleware you show sets req.isAuth to true or false and then calls next() to continue routing. All three code paths through that middleware just set req.isAuth and then call next(). Nowhere in this middleware does it do any redirect. So, if the core problem is too many redirections, that issue must be caused somewhere else by some other route/middleware that actually does a redirect, probably when it sees that req.isAuth is false since you said that the problem occurs when logged out or when the token is missing.
When redirecting, you have to make absolutely sure that when you redirect to a URL, there is ZERO chance (no code path of any kind) that the route handler for that URL will also redirect to that URL. That's how you get into a redirect loop.
Looking at the other routes you show, if the too many redirects issue is when redirecting to /user/login, then it seems likely the problem is in the authController.login() handler from this route:
router.get("/user/login", isAuthenticate, AuthController.login);
If the code for that route checks req.isAuth and redirects in any circumstances, then that would be an endless redirect loop.
If you need further advice, please provide the following information:
Which exact redirect URL is causing the problem of too many redirects? Is is /user/login?
Show us the code for the route that does that redirect because that's apparently where the fault is.

I don't want to send form data back with express, but it does, or does it?

I know the title of this question might sound confusing, but my problem is actually simple. I have these two handlers for /login get and post requests:
loginRender(req, res) {
let options = { title: 'Login', layout: 'auth.hbs' }
res.render('login', options)
}
login (req,res){
let user = Routes.findUser(req.body.username)
let passwordCorrect = Routes.hashCompare(
req.body.password,
user.password
)
if (passwordCorrect) {
let token = Routes.jwtsign(req.body.username)
let refreshToken = Routes.jwtRefreshToken(req.body.username)
Routes.authRedirect(res, token, refreshToken)
} else {
Routes.badRequestRedirect(res, '/login')
}
}
authRedirect(res, token, refreshToken )
{
let options = {
cssPath: 'styles/querystyle.css',
}
res.cookie('access_token', `${token}`, { httpOnly: true })
res.cookie('refresh_token', `${refreshToken}`, { httpOnly: true })
res.status(200).render('query', options)
}
// app.use(urlencoded)
// app.use(cookieParser)
// app.post('/login', login)';
// app.get('/login', loginRender)
Please, ignore all unrelated stuff.
So, everytime I complete login, I get my webpage rendered and I can actually open inspector and see this:
Page Inspector
Address line
How can I fix that? I want my user to be redirected to dashboard-like page and not to receive his sensitive data in insecure form.
UPD
there's also auth middleware that only appends req.username in case we did parse jwt successfully, and there's a little bit of interaction with it, but it does not appear on page until I go to this page manually by writing the address in address line.
If you don't send the data to the Express server, then you can't read it in you login function and you can't authenticate the user.
It is not a problem is the user can use the tools in their own browser to inspect the data that they entered.
You need it to be encrypted in transport (i.e. use HTTPS and not plain HTTP, at least in production) but you don't need to worry about the user finding out their own password.

Use Middleware to route user to the correct page. Given values from POST method exist in database

I am trying to use Middleware to check if the user entered the correct log in credentials to be routed to essentially the same page.
Goal: Have a log in page that takes user email and password. Check DB if account exists.
If yes, then display the username on the top right hand corner of the navigation bar.
My server.js code handling the checking of the values passed from POST.
router.post('/logInDynamic', (request, response, next) => {
var email = request.body.email;
console.log(email);
if (email === 'Alex') {
next();
{
response.setHeader('Content-Type', 'application/json');
response.render('logInDynamic', {
showUserInfo: true,
layout: 'login',
});
}
}
});
I am also getting this exception here below.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
It looks like you are calling next() before setting the header and rendering. So the next middleware function starts running before this one finishes.
Essentially, that error means that your api has sent a response back to the client with the headers already so you can't overwrite it.

How to send the home page after hiting a specific route [Express/Nodejs]

I'm trying to redirect to the home page after a user hit this route: /ref=123 but I want to keep that baseUrl, this is what I have so far:
I am requiring in my server.js file this: const referred = require('./routes/referred').
app.use('/ref=:id', (req, res, next) => {
res.locals = req.params.id
}, referred)
So, when a user hits the above route I am doing some validations in my referred.js file. Actually I need to send some kind of response telling whether that provided id exist or not but showing anyways the home page which is a simple login/resgistration form.
referred.get('/', (req, res, next) => {
//doing validations with res.locals
next() //<- calling the next middleware
})
after calling next() I put that middleware just below to redirect to the home page.
not sure if this is possible: app.use(express.static(_dirname + '/dist')) it seems like is not because I'm getting a 404 .
I know I could use the req.redirect() function but that will actually made a new request to the server and refresh the page erasing the baseUrl that I want to keep up there.
How do you render/send your pages?
You could use res.sendFile('path/to/page.html') to send back any html file while keeping the request URL.
If you want to display a dynamic message on the home page, you should use a viewing engine like ejs. If you are already using an engine, you can do something like
res.render('path/to/page', { status: 'This id does not exist!'})

Unexpected behavior when validating a session token using parse.com

I'm trying to build a simple application with parse.com as my user manager.
I would like to make a login call to parse.com from my client side, and call my node.js server with the user's session token (I'll add it as a cookie). In the server side, I'll validate the session (using https://parse.com/docs/rest#users-validating) and allow access only if the session is valid.
For example (in my server):
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
if(tokenIsValid(token)) {
next();
} else { // Redirect... }
});
app.get('/api/doSomething', function(req, res) {
// Do something....
});
the tokenIsValid(token) function should be implemented using https://parse.com/docs/rest#users-validating.
However, it seems that the REST API user validation returns the user even if the user is logged out (expected to return 'invalid session').
Is this a bug in the REST API user validation? What am I doing wrong? Is there a better way for doing that?
Thanks!
Via REST there's no concept of sessions really. REST calls are meant to be stateless meaning that the (current) user at /me will be serialized from the token provided. If the token is associated to a user it will return the JSON representation of that user otherwise in returns an error.
One way or another that call is asynchronous so you can't really use it in and if statement.
You can do:
app.get('/api', function(req, res, next) {
var token = getTokenFromRequest(req);
serializeUserFromToken(token,function(err,parseResponse) {
if(err) return next(err)
if(parseResponse.code && parseResponse.code === 101){
// called to parse succedded but the token is not valid
return next(parseResponse);
}
// parseResponse is the current User.
next();
});
});
Where serializeUserFromToken makes a request to Parse with the token in the X-Parse-Session-Token header field.

Categories