jwt accessing private page after login works on postman, but not on ejs view - node.js

I have the backend of a little register/login project on node, which works fine on postman, I'm doing the frontend using just ejs views, the registration works fine and the login alone too, but if I go to the private page, that works with the jwt token, it doesn't find the token I supposedly got when logged in, console says it's undefined.
This is the verification code.
const jwt = require('jsonwebtoken');
module.exports = function (req,res,next){
const token = req.header('auth-token');
console.log(token);
if(!token) return res.status(401).send('access denied');
try {
const verified = jwt.verify(token,process.env.TOKEN_SECRET);
req.user = verified;
//see private content
next();
} catch (err) {
res.status(401).send('invalid token');
}
}
this is the backend of the posts page
const router = require('express').Router();
const verify = require('./verifyToken');
//the verify marks this content as private
router.get('/',verify,(req,res)=>{
res.render('posts.ejs');
});
module.exports = router;
On postman I fill the token name on the headers, but how can I do something like this on the actual thing?

I searched a bit on this and we cannot pass headers to a url.
You can check out this question
Adding http request header to a a href link
When doing an ajax request however we can do attach custom headers and all that. We have full control over the request. I will advise you to use sessions in place of jsonwebtokens. Json Web Tokens are mostly used when using a Front End Framework React, Angular etc because we have to make ajax requests. We than save the token in localStorage and send the token in every subsequent request in the header.

Related

When the browser send cookies not received from the express server

I'm Developing a full-stack web application with Node js and express js as the backend and using Next Js for the front end and JWT for the authentication, I'm setting the JWT token with the cookie in the browser. The cookie is set successfully in the browser, but whenever I try to get the cookie from the Express server to check whether the user is valid or not, the cookie does not receive from the browser. I tried several ways to get the cookie from the browser but it doesn't respond. but it is receiving the cookie token from the Postman/thunder client.
note: The frontend port is 3000 and the backend port is 5000.
You can suggest another way for the user authentication with next js with external express server.
res.cookie("userToken", token, {
expires: new Date(Date.now() + 9000000000),
})
and the JWT verify code is here
const jwt = require("jsonwebtoken");
const jwtToken = (req, res, next) => {
try {
const userToken = req.cookies?.userToken;
if (userToken) {
const verify = jwt.verify(userToken, process.env.JWT_SECRET);
req.user = verify;
}
next(); // for getting the api result back to client
} catch (error) {
next(error);
}
};
module.exports = jwtToken;

How to save and send JWT token from frontend

I am using JWT in my node.js app. Everything with token works fine. I can get a token when I have logged in.
Here's how I check user auth.:
const jwt = require('jsonwebtoken')
try{
const token = req.headers.authorization
const decoded = jwt.verify(token, 'secret')
req.userData = decoded
next()
}
catch(err){
return res.send("Auth error")
}
I can access protected routes if I change token value with that token I've got after log in.
But I want to save the token (on user's side???), and each time when the user tries to access protected routes (from frontend), send token as req.headers.authorization, so that the token can be verified, and the user can access the route.
So, how to save and later send the token, that has been generated after user's log in each time when protected routes are linked to?
Thank you.
(I am not using any javascript frontend frameworks)
If it's a token for authentication, you can use a httpOnly cookie to prevent XSS attacks, which is a risk with local storage.
To save a JWT in a cookie in express:
const accessToken = jwt.sign();
return res
.status(201)
.cookie("accessToken", accessToken, {
httpOnly: true,
maxAge: (1000*60*5), // 5m
secure: true,
signed: true
})
.end();
When getting from requests:
const { accessToken } = req.signedCookies;
Inside your app.js:
const express = require("express");
const cookieParser = require("cookie-parser");
const app = express();
app.use(cookieParser("secret"));
With httpOnly cookies your requests automatically send the cookie along with the request (only if the cookie belongs to the same domain). Just make sure your CORS and http client are properly configured to handle the cookie
Common approach to save it to a local storage. Just keep in mind local storage size and other limitations in different browsers.

req.cookies get overwritten when make request using nextjs

I'm trying to make a request to the express/nodejs backend using nextjs
in pages/reader.js, I have
Reader.getInitialProps = async ({query}) => {
const res = await fetch('http://localhost:3000/api/books/reader/' + query.id);
const json = await res.json();
return {book: json}
};
Unfortunately, that overwrites the cookies stored in the request object on the backend. When I do a console.dir(req.cookies) in the backend node js, express code, I get undefined in book.js where the reader code is.
How can I fetch without overwriting the request object in the express backend?
Look at the example in https://github.com/zeit/next.js/blob/canary/examples/auth0
In the file ssr-profile.js it shows how you can forward your cookies in the request to the server:
// To do fetches to API routes you can pass the cookie coming from the incoming request on to the fetch
// so that a request to the API is done on behalf of the user
// keep in mind that server-side fetches need a full URL, meaning that the full url has to be provided to the application
const cookie = req && req.headers.cookie
const user = await fetchUser(cookie)

Correct way to call passport js function from react component

Hello I am new to react and Nodejs. Currently I am trying to make a login component in react which contains a button through which app can authenticate the user through Facebook. I am using passport.js for authentication. I am also using reflux for handling any api call to node server.
Below is the respective code for each
actions.js
var Reflux = require('reflux');
module.exports = Reflux.createActions([
"facebookLogin"
]);
store.js
var Reflux = require('reflux');
var Actions = require('../actions');
var Api = require('../utils/api');
module.exports = Reflux.createStore({
listenables: [Actions],
facebookLogin: function(email) {
Api.FBrequest(email)
.then(function(response){
console.log('returned user for facebook from server : ' + response);
}.bind(this));
}
});
api.js
module.exports = {
FBrequest: function() {
return (
fetch('/auth/facebook', {
method: 'get'
}).then(function(response){
return response.json();
})
);
}
};
facebook.js
// file at server for handling passport authentication calls
module.exports = function(app, passport){
// call to facebook for authenticating user
// in response to this call, facebook will reply in /auth/facebook/callback with the user object
app.get('/auth/facebook', passport.authenticate('facebook', {scope:'email'}));
// TODO return error on failure of login instead of navigating to the login route
app.get('/auth/facebook/callback', passport.authenticate('facebook',
{failureRedirect: '/login'}), function(req, res){
// user successfully authenticated by facebook
// return the user object
return req.user;
});
};
When I click the fbLogin button on my app I get the following error
Fetch API cannot load https://www.facebook.com/v2.2/dialog/oauth?response_type=code&redirect_uri=…3A3000%2Fauth%2Ffacebook%2Fcallback&scope=email&client_id=1807765906116990. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I want to know that is it correct approach to use fetch for directly sending the get to server for '/auth/facebook' and let the server handle the request and return with user object. If it is then where this is going wrong ? If it is not then what is the correct approach for achieving the same with react?
For anyone else who stumbles upon this question like I did tonight - we solved this error by having the login button wrapped in an a href tag - which then takes the user to our authorization route. Once the user is authorized, facebook then returns the user to us. Then, every time our component mounts, we make sure the state has our logged in user mounted. If it doesn't we make a get request via axios to a route which passes back the user object, and we set our state appropriately.

Is it possible to use validation with express static routes?

I'm using jwt token validation in my project to protect some importent data:
if (req.headers.auth) {
var token = req.headers.auth.split(' ')[5];
var payload = jwt.decode(token, 'blablabla...');
if (!payload.sub) {
res.status(401).send({
message: 'Authentication failed'
});
}
if (!req.headers.auth) {
return res.status(301).send({
message:'You are not authorized'
});
}
res.send(data);
} else {
res.header(404).send('Go away!');
}
Is it possible to use this method to protect the static rout, added using express static middleware?
UPDATE!!!
Ok, now jwt token validation set on my static route. But I have got another problem - how to send this token to node.js server BEFORE my angular app uploaded (beacose now it is blocked with new middleware) and started to insert tokens in to the http headers. Do I need some extra module, or maby my new middleware can request somehow that jwt token from the browser?
Yes, you can attach an extra middleware to execute for your express static resources like this:
var staticMiddleware = function(req, res, next) {
console.log('Hello from staticMiddleware!');
next();
};
app.use(staticMiddleware, express.static(__dirname + '/public'));
Note that if you do add this JWT token checking middleware you should only be returning a response in this code (eg res.send()) if authentication fails. If the JWT is valid, to allow the code to proceed to the static route, call next().
I would have two additional notes regarding your code:
Your if(!req.headers.auth) block will never be executed, you're already in side an if(req.headers.auth) block.
In all failure cases here (req.headers.auth is missing, or payload.sub is missing) you should return a 401 Unauthorized. 301 and 404 would both be incorrect.

Resources