method in express js get() - returns undefined - javascript

I have this Node.js code that should, using Express.js http get, decode my jwt token from my http auth header.
When I write the code of decodeToken() inside of my express js get() method, everything works fine.
When I extract it to outside method (decodeToken() method) I get that undefined value from this method. Mind you, when this code was hard coded inside of the method get() it works.
Why is that, the async nature of Node.js? Does the method finish after the get() method was supposed to assign the token?
If I will use promises, will it solve that?
var jwtCheck = expressJwt({
secret: "some secret"
});
app.use('/test', jwtCheck);
app.get('/test', function (req, res) {
var token = req.get('Authorization').split("Bearer ")[1];
var information = decodeToken(token)
console.log("information: "+information);
if (information!=null) {
res.json(information);
}
else {
res.json('Failed to authenticate token.');
}
});
var decodeToken = function (token) {
console.log(token);
jwt.verify(token, secret, function (err, decoded) {
if (err) {
console.log('Failed to authenticate token.');
return null;
} else {
return (decoded);
}
});
}
var getToken = function (req) {
return req.get('Authorization').split("Bearer ")[1];
}

jwt.verify is async because you pass a callback to it so anything that calls it needs to handle that. You could look at promises to clean up the logic a little bit but just using the code you have you could modify it like this:
var jwtCheck = expressJwt({
secret: "some secret"
});
app.use('/test', jwtCheck);
app.get('/test', function (req, res) {
var token = req.get('Authorization').split("Bearer ")[1];
// pass callback to decodeToken that gets called after the token is verified
decodeToken(token, function(information) {
// this function won't execute until decodeToke calls it as `next()`
console.log("information: "+information);
if (information!=null) {
res.json(information);
}
else {
res.json('Failed to authenticate token.');
}
})
});
// accept `next` callback
var decodeToken = function (token, next) {
console.log(token);
jwt.verify(token, secret, function (err, decoded) {
if (err) {
console.log('Failed to authenticate token.');
return next(null);
} else {
return next(decoded);
}
});
}
var getToken = function (req) {
return req.get('Authorization').split("Bearer ")[1];
}

Related

Problem while fetching a route from another route

I have a route to check if a user is logged in. It works well, but I don't understand what is the problem if I create a second route just below that calls it just to do the same thing. It seems like I can't access the cookie anymore in the second route, but I don't know why. Thanks for your help !
// This route works :
router.get('/loggedin', async (req, res) => {
try {
const token = req.cookies.jwt;
console.log("token : " + token) // Token is correct here in loggedin route, but is undefined if I use the route below
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
if (decodedToken) {
res.send(true);
}
else {
res.send(false);
}
}
catch (err) {
res.status(500).send(false);
}
});
// This route calls the route above and doesn't work
router.get('/loggedinbyanotherway', async (req, res) => {
const checking = await fetch(`${process.env.API_URL}:${process.env.PORT || 3000}/loggedin`)
console.log(checking.ok) // Returns false
const data = await checking.json()
console.log(data) // Returns false
res.send(data)
});
Your fetch request isn't providing any cookies, so how could the code handling the request read any cookies?
More to the point... This entire operation is unnecessary. Why make an HTTP request to the application you're already using? Instead, extract the functionality you want into a common function and just call that function from both routes. For example:
const isLoggedIn = (req) => {
const token = req.cookies.jwt;
const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
if (decodedToken) {
return true;
} else {
return false;
}
};
router.get('/loggedin', async (req, res) => {
try {
res.send(isLoggedIn(req));
}
catch (err) {
res.status(500).send(false);
}
});
router.get('/loggedinbyanotherway', async (req, res) => {
const checking = isLoggedIn(req);
res.send(checking);
});
In the example it's not really clear why you need the second route or what else it offers, but I can only assume it's just a placeholder for some additional functionality you plan to add.
Either way, the point is that the application doesn't need to make an entire HTTP request to itself, since you're already in that application and have access to the same logic.

Middleware authentification with a condition not working Express. Node.js

I am currently developing a website with an API that I built with node.js, express and MongoDb for the database.
I am curretly learning node and express and cant find my way to create a middleware to verify that the USER ID matches the POSTED BY ID from a COMMENT. That way the USER can only delete his own comments.
My middleware looks like this
verifyUserIdPostedBy.js
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
},
}
My console.log() in the middleware show me exactly the 2 values that I want to compare but I get the error 'Stopped' and my verification never happens. I tried accesing the route with the comment owner and also with not the comment owner and none works
and my route looks like this
comments.js
const express = require('express');
const router = express.Router();
const Comment = require('../models/Comment');
const verify = require('./verifyToken');
const {verfyUserIdPostedBy} = require('./verfyUserIdPostedBy')
// DELETE COMMENT
router.delete('/:commentId', verify, verfyUserIdPostedBy, async (req, res) => {
try {
const removedComment = await Comment.deleteOne({ _id: req.params.commentId });
res.json(removedComment);
} catch(err){
res.json({message:err});
}
})
Like I said I am new at this but cant find a way to do it properly.
Appretiate in advance any help and advice.
Mario
I add comments in your code to explain how it works :
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
/* -----this is a callback function------ */
/* the code inside the callback function is executed only when findOne finish and **after** the code outside */
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
});
/* this code is executed before the code inside the callback function */
console.log(req.postedById); // undefined, you can check
console.log(userId);
if(userId !== req.postedById) // this is always true
return res.status(500).json({message: 'Stopped'}) // and this line always executes
return next(); // and this line never execute
},
The concept is callback. I strongly advise you to research this keyword, callback is used massively in NodeJS. Nowadays, there are Promise and async/await that allow developers to write asynchronous code in a "synchronous way", but callback is the base.
In order for your code works, 1 simple solution (there are many solutions!) is put comparison code into the callback block, something like :
const Comment = require('../models/Comment');
var userId
var postedById
module.exports = {
verfyUserIdPostedBy: function (req, res, next) {
userId = req.header('userId')
postedById = Comment.findOne({ _id: req.params.commentId}).populate('postedBy') .exec( function (error, body) {
if (error) throw new Error(error);
req.postedById = body.postedBy._id // assign the ID to the req object
console.log(req.postedById);
console.log(userId);
if(userId !== req.postedById)
return res.status(500).json({message: 'Stopped'})
return next();
});
},
}

Stronglooop loopback after remotehook couldn't modify response

I want to added extra details on login request and I have the following
module.exports = function(UserAccount) {
UserAccount.afterRemote('login', function(ctx, result, next) {
var response = [];
if (ctx.result) {
var userId = result.userId;
var token = result.id;
// attach user profile
UserAccount.findById(userId, function(err, user) {
if (err)
console.log(err);
if (user) {
response.profile = user;
response.accessToken = token;
ctx.result = response;
console.log(ctx.result);
return next();
}
});
}
});
};
the log just before the next() callback call logs correctly.
The problem is that is always returns empty response .
What is the problem ?
Just call next() instead of returning it. Also, modify ctx.res.body to modify the actual response body.

Cannot return values to response with mongoose/mongodb and nodejs

I am using Nodejs, ExpressJs, MongoDB via Mongoose. I have created a simple UserSchema . I have my code separated into multiple files because I foresee them getting complex.
The url '/api/users' is configured to call the list function in 'routes/user.js' which happens as expected. The list function of UserSchema does get called, but it fails to return anything to the calling function and hence no result goes out.
What am I doing wrong ?
I tried to model it based on http://pixelhandler.com/blog/2012/02/09/develop-a-restful-api-using-node-js-with-express-and-mongoose/
I think I am doing something wrong with the function definition of userSchema.statics.list
app.js
users_module = require('./custom_modules/users.js'); // I have separated the actual DB code into another file
mongoose.connect('mongodb:// ******************');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
users_module.init_users();
});
app.get('/api/users', user.list);
custom_modules/users.js
function init_users() {
userSchema = mongoose.Schema({
usernamename: String,
hash: String,
});
userSchema.statics.list = function () {
this.find(function (err, users) {
if (!err) {
console.log("Got some data"); // this gets printed
return users; // the result remains the same if I replace this with return "hello"
} else {
return console.log(err);
}
});
}
UserModel = mongoose.model('User', userSchema);
} // end of init_users
exports.init_users = init_users;
routes/user.js
exports.list = function (req, res) {
UserModel.list(function (users) {
// this code never gets executed
console.log("Yay ");
return res.json(users);
});
}
Actually in your code you are passing a callback, which is never handled in function userSchema.statics.list
You can try the following code:
userSchema.statics.list = function (calbck) {
this.find(function (err, users) {
if (!err) {
calbck(null, users); // this is firing the call back and first parameter should be always error object (according to guidelines). Here no error, so pass null (we can't skip)
} else {
return calbck(err, null); //here no result. But error object. (Here second parameter is optional if skipped by default it will be undefined in callback function)
}
});
}
Accordingly, you should change the callback which is passed to this function. i.e.
exports.list = function (req, res){
UserModel.list(function(err, users) {
if(err) {return console.log(err);}
return res.json(users);
});
}

Node.js - howto block around async call. Or non-blocking xmltojs lib

I'm over my head at the moment.
I'm new to node and writing a passportjs module for Freshbooks. There's a Passport function I'm trying to implement that get's a user's profile.
This code uses Passport's OAuth foo to make a request.
this._oauth.post(url, token, tokenSecret, post_body, post_content_type, function (err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
try {
var parser = require('xml2json');
var json = parser.toJson(body); //returns a string containing the JSON structure by default
var util = require('util');
console.log(util.inspect(json));
var profile = { provider: 'freshbooks' };
profile.id = json.response.staff.staff_id;
profile.displayName = json.response.staff.first_name + ' ' + json.response.staff.last_name;
profile.name = { familyName: json.response.staff.last_name,
givenName: json.response.staff.first_name };
if (json.response.staff.email) { profile.emails = [{ value: json.response.staff.email }]; }
profile._raw = body;
profile._json = json;
console.log(util.inspect(json));
done(null, profile);
} catch(e) {
done(e);
}
});
I get a response. It's xml. I'm converting it to JSON, but I don't want that actually. I want a plain-old javascript object.
I looked at https://github.com/Leonidas-from-XIV/node-xml2js but the examples don't show how to get the result out.
var parseString = require('xml2js').parseString;
var xml = "<root>Hello xml2js!</root>"
parseString(xml, function (err, result) {
console.dir(result);
});
What do I do to block around this code till the call is complete and get result out? I'm not sure how to merge these two callbacks together.
you can ask xml2json to return object:
var json = parser.toJson(body, {object: true});
if you decide to use async parser then just put your done callback inside json result handler. There is no need to "block" async function:
var parseString = require('xml2js').parseString;
parseString(body, function(err, json) {
// handle error: return done(err)
// do your logic if no error
// ...
// profile._json = json;
// ...
//
// 'return' result
done(null, profile);
});

Categories

Resources