I am trying to make a POST request to a nodejs server from an Ionic application work, but I stumbled on this error.
Http failure response for http://127.0.0.1:3000/services/user/signin: 500 Internal Server Error", SyntaxError: Unexpected token u in JSON at position 0;
I have access to both the application and the API server. Task at hand, trying to send credentials to the server, which will check if those credentials are recognized and will send a response. The server side code works just fine, since I have a web app accessing to the same resources and working like a charm.
Here goes the code.
Home page:
doLogin() {
this.remoteService.login(this.user);
}
user is a key value array
user = { email:'', password:'' };
Now for the login function in the remoteService injectable:
login(user){
let headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
console.log(JSON.stringify(user));
this.http.post(serviceUrl+'/user/signin', JSON.stringify(user), {headers: headers}).subscribe(
function(response) { console.log("Success Response" + response)},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log(err);
} else {
console.log(err);
}
}
);
}
I used this line
console.log(JSON.stringify(user));
to test the function argument for JSON correctness, and it's a charm.
Finally, this is the nodejs server code
if(label === 'signin') {
return function (req, res, next) {
{
var user = JSON.parse(req.query.user);
db.query('SELECT username as id FROM user where email = ? and password = ?', [user.email,user.password], function (err, result) {
if (err) {
next(err);
}
else {
if(result.length === 1) {
delete user.password;
req.session.user = result[0];
req.result = 400;
}
else
{
req.result = 404;
}
next();
}
});
}
};
}
Could you please help me fix the nasty error? I have been banging my head on this all day long and a big part of the last night.
Related
Building a simple ToDo app with ReactJs frontend and NodeJs/Express backend. I configured my frontend to include userId as a request header:
export default function authHeader() {
const user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
// return { Authorization: 'Bearer ' + user.accessToken }; // for Spring Boot back-end
return {
'x-access-token': user.accessToken,
'userid': user.id
}; // for Node.js Express back-end
} else {
return {};
}
}
This header is included with the Axios request:
// List all Group Members
listMembers() {
return http.get(`/group`, { headers: authHeader() });
}
Consequently, I can see the headers in the request:
Part of my auth middleware references the access token:
verifyToken = (req, res, next) => {
let token = req.headers["x-access-token"];
if (!token) {
return res.status(403).send({
message: "No token provided!"
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
req.userId = decoded.id;
next();
});
};
The req.headers lines near the top is able to pull the token from header "x-access-token" with no problem. HOWEVER - for debug purposes, I have tried to pull the header userId value instead using let token = req.headers["userid"]; but this simply comes back as undefined in my debug tools. Why can it pull x-access token header but not userId? My eventual goal is to refer to the req.header userId value in backend SQL queries, this is just a test.
It ended being a capitalization error somewhere in pipeline. #Sardar's comment was on the money, make sure everything is spelled correctly and matches case.
I am trying to put together a reactjs Dashboard and wire it up with a Nodejs back-end. I am currently trying to validate a jwt token. when I do it using a Postman app, its working fine. but when I try it using my reactjs form, its not happening. please help me find the problem in my code. I am not an experienced developer. I am kind of a newbie to both nodejs and reactjs.
Any help will be highly appreciated.
I will try to post all the relevant code and some snapshots below.
//reactjs code calling this function on a button submit
//verify user
onVerify = event => {
let databody = localStorage.getItem("jwtToken");
event.preventDefault();
console.log(databody);
fetch("http://localhost:8000/api/auth/me", {
method: "get",
headers: {
"x-access-token": databody
}
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw new Error("Something went wrong with your fetch");
}
})
.then(json => {
console.log(json.token);
});
};
Nodejs express backend code
//app.js
var express = require("express");
var db = require("./db");
var Cors = require("cors");
var app = express();
app.use(Cors());
var UserController = require("./user/UserController");
app.use("/users", UserController);
var AuthController = require("./auth/AuthController");
app.use("/api/auth", AuthController);
var WorkInvenController = require("./auth/WorkInvenController");
app.use("/api/workinven", WorkInvenController);
module.exports = app;
//AuthController.js
router.get("/me", function(req, res) {
console.log(req.headers);
var token = req.headers["x-access-token"];
if (!token)
return res.status(401).send({ auth: false, message: "No token provided." });
jwt.verify(token, process.env.secret, function(err, decoded) {
if (err)
return res
.status(500)
.send({ auth: false, message: "Failed to authenticate token." });
User.findById(decoded.id, { password: 0 }, function(err, user) {
if (err)
return res.status(500).send("There was a problem finding the user.");
if (!user) return res.status(404).send("No user found.");
res.status(200).send(user);
});
});
});
terminal output from the backend when posted using Postman
terminal output from the backend when posted using reactjs from
browser error attached below
as i can see its a "rejection error"
you can just add .catch() and handle the error that is being thrown.
onVerify = event => {
let databody = localStorage.getItem("jwtToken");
event.preventDefault();
console.log(databody);
fetch("http://localhost:8000/api/auth/me", {
method: "get",
headers: {
"x-access-token": databody
}
})
.then(res => {
if (res.ok) {
return res.json();
} else {
throw new Error("Something went wrong with your fetch");
}
})
.then(json => {
console.log(json.token);
}).catch(error=>{
//handle the error in here may be
console.log(error)
});
};
sometime we wrote some sort of wrapper as well to handle errors:
fetch(<url>, {
<headers>,
<options>
})
.then(this._checkStatus)
.then(response => response.json());
_checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
// Success status lies between 200 to 300
return response;
} else {
//here handle the error may be.
var error = new Error(response.statusText);
console.log(error);
}
}
so in your case, when the error coming its not handled , as there no .catch found, its throwing unhandled rejection error.
you can look at the above methods and follow any of them , also let me know if you are still facing issue with this.
sorry that I didn't post the whole code up here, or else I am sure you guys would have figured it long time back. long story short..
the problem was with my token, I accidentally set the expiresIn to 60 thinking that it was 60 minutes instead of 60 * 60. so the token was expiring every next minute.
Now after setting the token expiry to "24h" everything seems working good..
thanks a lot for you help guys.
rooms.js -> controller class for rooms endpoint
router.get('/:roomid/fight/verify', function(req, res) {
roomModel.authenticateUserForFight(req.params.roomid, req.query.otp, res);
});
roomModel -> model class for rooms
//authenticate user based on otp provided on client side
exports.authenticateUserForFight = function(roomid, otp, res) {
db.query('select * from room where roomid=?', [roomid], function(error, rows) {
if (rows.length == 0) {
console.log("otp does not exist in db for room:" + roomid);
} else if (rows.length == 1) {
var otpInDb = rows[0].otp.toString();
if (otp == otpInDb) {
console.log("User is authorised");
res.status(200);
res.send("User is authorised");
} else {
console.log("User is unauthorised");
res.status(401);
res.send("User not authorised");
}
}
});
}
This piece of code works fine but is there a better way to send response to client instead of passing res object to model class and setting the status and response message there ? The reason i am passing the res object is because doing res.status and res.send in controller is giving issues as the db call is asynchronous. Suggest some better practices to handle these kind of situtations.
You are right. You should not pass the res object. Its a debugging nightmare if there is more than one place from where the function can exit. Its far better that the subsequent functions return the value and the controller responds to the status.
You can simply create a callback method which will be called once the async db query is completed. Something like this
router.get('/:roomid/fight/verify', function(req, res) {
const callback = (status, message) => {
res.status = status
res.send(message);
}
roomModel.authenticateUserForFight(req.params.roomid, req.query.otp, callback);
});
and the main function can just call this function
//authenticate user based on otp provided on client side
exports.authenticateUserForFight = function(roomid, otp, callback) {
db.query('select * from room where roomid=?', [roomid], function(error, rows) {
if (rows.length == 0) {
console.log("otp does not exist in db for room:" + roomid);
} else if (rows.length == 1) {
var otpInDb = rows[0].otp.toString();
if (otp == otpInDb) {
console.log("User is authorised");
callback(200, 'user authorized');
} else {
console.log("User is unauthorised");
callback(401, 'user not authorized');
}
}
});
}
this is the updated code
if (otp == otpInDb) {
console.log("User is authorised");
res.json({
status:200,
message:"user authorized"
})
} else {
res.json({
status:401,
message:"user not authorized"
})
}
It is always better to send your response in envelope. and I can see you are using String like queries. Use orm wrapper like sequelize to prevent SQL injection attacks
I'm new to Sails.js and I was trying to make a filter to authorize using a Bearer token which come from a higher server, a gatekeeper which is responsable to do the OAuth2 authentication from GitHub API. The services streams works well. I'm already aware of Passport.js but I'm trying to implement this on my own. I came with a policy which looks like:
module.exports = function (req, res, next) {
var httpsExec = require('https');
if (req.headers.authorization) {
var parts = req.headers.authorization.split(' ');
if (parts.length == 2) {
var tokenType = parts[0]
, credentials = parts[1];
if (/^Bearer$/i.test(tokenType) || /^bearer$/i.test(tokenType)) {
httpsExec.request({
host: 'api.github.com',
post: 443,
path: '/user',
method: 'GET',
headers: {'Authorization': 'token ' + credentials, 'User-Agent': 'curly'}
}, function (response) {
var responseData = '';
response.setEncoding('utf8');
response.on('data', function (chunk) {
responseData += chunk;
});
response.once('error', function (err) {
next(err);
});
response.on('end', function () {
try {
req.options.user = JSON.parse(responseData);
next();
} catch (e) {
res.send(401, {error: e});
}
});
}).end();
} else {
console.err("The token is not a Bearer");
res.send(401)
}
}
} else {
res.send(401, {error: "Full authentication is necessary to access this resource"})
}
};
The policy is called once I hit the controller route but it throws a _http_outgoing.js:335
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
And the process is terminate.
The problem I think is the next() and the returns I tried everywhere I think, to put the next() call, but still gives me this error, if I remove then I lock the request on the policy.
EDIT
I did a simple sample of policy where I just set some property on req.options.values and happened the same problem, so maybe could be an issue with req.options.requestData = JSON.parse(responseData); ? How else could I set a property to send to controller ?
response.once('error', function (err) {
next(err);
});
response.on('end', function () {
try {
req.options.user = JSON.parse(responseData);
next();
} catch (e) {
res.send(401, {error: e});
}
});
both are getting executed.to check console.log("something") in error to see if there is error.
This happens when you're trying to modify the request and response together or modify one of them twice.
In your code, I think the callback is being called twice and you are also modifying the response at the same time. Check the lines where you're calling callback "next()". You'll find your issue.
My express app uses the following basic auth function:
exports.basicAuth = express.basicAuth(function (user, pass, callback) {
findUserByEmail(user, function (err, account) {
var isPasswordMatch = false;
log.info("Authenticate request user-pass: " + user + ":" + pass);
if (err) {
log.info("Error occurred when authenticate user: " + err);
}
if (account == null || account == undefined) {
log.info("Account not found");
} else {
if (!isActive(account)) {
log.info("Account is not active");
}
if (account.password != encryptPassword(account.salt, pass)) {
log.info("Wrong pass");
isPasswordMatch = false;
} else {
isPasswordMatch = true;
}
}
var authenticated = err == null && account != null && account != undefined && isActive(account) && isPasswordMatch;
callback(null, authenticated);
});
});
Sometimes, when the server is overloaded the findUserByEmail request will fail. In this case, the function above causes the server to return a 401 error. Instead, I want to return a 5XX error code, so that clients know that there is a problem at the server, not necessarily with the credentials they passed. What is the best way to cause an error in findUserByEmail to return a 5XX error code instead of a 401?
I found a solution. I just wrapped the authentication handler in a standard request handler and send an error response if something goes wrong.
exports.basicAuth = function(req, res, next) {
express.basicAuth(function (user, pass, callback) {
findUserByEmail(user, function (err, account) {
var isPasswordMatch = false;
log.info("Authenticate request user-pass: " + user + ":" + pass);
if (err) {
log.info("Error occurred when authenticate user");
res.send(500, { error: 'Unable to authenticate request' });
return;
}
...
});
})(req, res, next);
};