Error "Unexpected token P in JSON at position 0 in fetch" - json

I created a signup form, In this I'm posting data from react client to the node server where I created a signup route to handle that signup form.
Here we are posting data to the server.
async function submitHandler(e){
e.preventDefault();
try{
const response = await fetch("/signup", {
method: "POST",
body: JSON.stringify({
name: name,
email: email,
password: password
}),
headers: {
"Content-Type": "application/json"
}
})
console.log(response);
const data = await response.json();
if(data.error){ //This code of line to make sure that if there is any error then it should be catchable by the catch block.
throw new Error(data.error);
}
}
catch(e){
console.log(e.message); //Here I'm getting error -> unexpected token p in JSON at position 0.
}
}
This is the route where I'm posting data.
router.post("/signup", async(req, res) => {
const {name, email, password} = req.body;
try{
const XYZ = await User.ValidatingUser(name, email, password); //Here we are calling a function to check email exist or not before create an account.
const user = new User({
name: name,
email: email,
password: email
})
await user.save();
return res.send("Posted successfully");
}
catch(e){
return res.json({error: e.message});
}
})
This is the function which I'm calling in the signup route to check email is exists or not.
//This code is to check that email exists or not. If the email exists then you can't signup.
userSchema.statics.ValidatingUser = async(name, email, password) => {
if(!name || !email || !password){
throw new Error ("Please add all the fields");
}
const user = await User.findOne({email: email});
if(user){
throw new Error("That email is already exist");
}
}
When I click on the signup submit button, first it shows error -> unexpected token P in JSON at position 0.
But When I again clicked on the signup submit the form then it will show this error -> That email already exists (which is returned by our server).
So it means data is saving in our DB.
See this Image.
enter image description here

I find it.
It was difficult but it's res.send("Posted successfully"); the issue.
You are to send a string as JSON, which is NOT JSON.
So, basically you have to do like:
res.send({message: "Posted successfully"});
Just: try to don't duplicate.

Related

Why my password in the database is not equal to the password in the request body?

I try to make a login for my API in Nestjs, so when the user send the data through the request body, I catch the data and I use the query builder of typeorm, then I get the user with his properties, after comproving if user exists I create a new comparison block, I don´t know the reason why the code is not work, if I use https://bcrypt-generator.com/ for comparate the hash password in the database and the password of the request body, that throw true, but in my code it doesn't work
async login(userRO: UserRO) {
const { email, password } = userRO;
const user = await getRepository(User)
.createQueryBuilder('user')
.where('user.email = :email', {email})
.getOne();
if (!user) {
throw new HttpException(
'Usuario no es correcto',
HttpStatus.BAD_REQUEST,
);
}
// hashPassword = $2y$12$ZvWFRLVoS2gxyCjLkCbOZuN7NKfYrpT6cWxSJaeiVr0PnPBeoI8GS
// password = pepito09
const pass = await bcrypt.compare(password, user.password);
if (!pass) { // this always throw an error
throw new HttpException(
'Contraseña incorrecta',
HttpStatus.BAD_REQUEST,
);
}
const rol = await getRepository(Rol)
.createQueryBuilder('rol')
.select('rol.name')
.leftJoinAndSelect(User, 'user', 'user.rolId = rol.id')
.where('user.email = :email', { email })
.getOne();
if (!rol) {
throw new HttpException(
'Rol no encontrado',
HttpStatus.NOT_FOUND,
);
}
const type = this.typeUser(rol.name) ;
const payload = { email: user.email, id: user.id, rol: rol.name };
return {
access_token: this.jwtService.sign(payload),
type,
};
}
So, I expect the comparison block about the password throw true if the password in the database and the password in the request body are equals, and false if it doesn't.
At the moment, always throw true

Passing authentication token to HTML pages

I have a user authentication system that generates an access token upon successful authentication. I need to pass this token to other pages as the header parameter to allow usage of that page.
module.exports.authenticate=function(req,res){
var email=req.body.email;
var password=req.body.password;
connection.query('SELECT * FROM org WHERE email = ?',[email], function (error, results, fields) {
if (error) {
res.json({
status:false,
message:'query error'
})
}else{
if(results.length >0){
if(bcrypt.compareSync(password, results[0].password)){
var access_token = jwt.sign({ id: email }, 'secretpassword123', {expiresIn: 3600});
var decoded = jwt.decode(access_token, 'secretpassword123');
var expires_in = decoded.exp-decoded.iat;
var token_type = "org";
console.log(decoded);
req.headers.access_token = access_token;
res.cookie('access-token', access_token, { expires: new Date(Date.now() + 3600)})
res.status(200).send({ auth: true, access_token: access_token, expires_in, token_type});
}
else{
res.json({
status:false,
message:"Email or password does not match"
});
}
}
else{
connection.query('SELECT * FROM client WHERE email = ?',[email], function (error, results, fields) {
if (error) {
res.json({
status:false,
message:'query error'
})
}else{
if(results.length >0){
if(bcrypt.compareSync(password, results[0].password)){
var access_token = jwt.sign({ id: email }, 'secretpassword123', {expiresIn: 3600});
var decoded = jwt.decode(access_token, 'secretpassword123');
var expires_in = decoded.exp-decoded.iat;
var token_type = "client";
//res.status(200).send({ auth: true, access_token: access_token, expires_in, token_type});
connection.query('UPDATE client SET fingerprint = ?', access_token, function(error, results, fields){
if(error){
console.log(error);
}
else{
console.log(results);
}
})
return res.redirect('/dashboard.html');
}
else{
res.json({
status:false,
message:"Email and password does not match"
});
}
}
else{
res.json({
status:false,
message:"Email does not exist"
});
}
}
});
}
}
});}
I want to pass the access-token to other pages and controllers as a way to authorize.
For example, this is my get-user controller:
module.exports.getUser = function(req,res){
var email = req.body.email;
req.headers.access_token = authenticate.authenticate.access_token
connection.query('SELECT clientid, email, orgid, name, phone, type, role, fingerprint, verified FROM client WHERE email = ?', req.body.email, function(error,results, fields){
if(error){
console.log(error)
res.redirect('/dashboard.html');
}
else{
console.log(req.headers)
console.log(results)
//res.redirect('/dashboard.html');
res.status(200).send(results);
}
})
}
How should I approach this?
I have added res.cookie to the authentication module, and I can see that the cookie gets stored in the browser. But when I try to read the cookie in another page with req.cookies or req.signedCookies it says undefined.
I ended up using localStorage to store the tokens. This is obviously not secure by oAuth standards, but it works. How can I use cookies to get the same functionality as local storage. I need to use the token generated in the authentication module to verify authorization in other pages.
This is usually achieved using cookies. After a cookie is set, it will be attached to every request the browser makes to the server. E.g. if you're using a framework like express, you could do something like
res.cookie('access-token', access_token, { expires: new Date(Date.now() + 300000), httpOnly: true })
But actually this is just a convenience method to add the "Set-Cookie"-HTTP-Header to your response, which causes the browser to create a cookie: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
Btw, for security reasons you should probably set the 'Secure' and the 'HttpOnly' flags, which make sure, that the cookie is only sent using TLS (HTTPS) and cannot be read by JavaScript respectively. The 'SameSite'-Directive is also useful for preventing CSRF attacks.

POSTing json to API with Angular 2/4

I am new to angular 4 and REST API development. I have developed a Login API in back-end and it works fine when I call it using Postman:
In the front-end application which is an Angular 4 project, I have created a service to call this login API. Here is the method I created in this service:
sendCredential(username: string, password: string) {
const url = 'http://localhost:8080/authenticate/user';
const body = '{"username": "' + username + '", "password": "' + password + '"}';
const headers = new Headers(
{
'Content-Type': 'application/json'
});
return this.http.post(url, body, {headers: headers});
}
My first question is:
Is this the correct way to pass the json object and call this API?
And I also created a component which calls the method in the service. Here is the method/event-handler I created in this component:
onSubmit(uname: string, pwd: string) {
this.loginService.sendCredential(uname, pwd).subscribe(
res => {
this.loggedIn = true;
localStorage.setItem('PortalAdminHasLoggedIn', 'true');
location.reload();
},
err => console.log(err)
);
}
My second question is:
How should I check whether a token is returned back or an error?
Question 1:
You do not need to stringify the body object when you do a http.post() in angular. Just use a normal object will do, and the Http class will help you parse it internally:
sendCredential(username: string, password: string) {
const url = 'http://localhost:8080/authenticate/user';
//do not need to stringify your body
const body = {
username, password
}
const headers = new Headers(
{
'Content-Type': 'application/json'
});
return this.http.post(url, body, {headers: headers});
}
Question 2:
As for your error, note that Angular also catch every http error. and by http error, it means that any status code that is <200 or >=300 will be an error. So only status codes that is in between 200 and 300 is considered successful. Upon an error received, angular will throw an Observable error, which you will need to handle explicitly (which you did it correctly):
onSubmit(uname: string, pwd: string) {
this.loginService.sendCredential(uname, pwd).subscribe(
res => {
//token should be in your res object
this.loggedIn = true;
localStorage.setItem('PortalAdminHasLoggedIn', 'true');
location.reload();
},
err => {
//handle your error here.
//there shouldn't be any token here
console.log(error);
}
);
}
With your above code, you should receive your token in your successful callback, and it will be in the res object. If there's an error, no token should be received and you should handle the error at the error callback.

Error function not returning JSON format

I'm trying to pass a JSON error object into my code using the error function in two cases. Once in the email and password check statement and again in the if existingUser statement. I think it's just that time of the night.
const User = require('../models/user');
exports.signup = function(req, res, next) {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.err("Please enter in email and password");
}
//See if a user with the given email exists
User.findOne({ email: email }, function(err, existingUser) {
if (err) { return next(err); }
//If a user with email does exist, return an Error
if (existingUser) {
//the status sets the status of the http code 422 means couldn't process this
return res.err( 'Email is in use' );
}
//If a user with email does NOT exist, create and save user record
const user = new User({
email: email,
password: password
});
user.save(function(err) {
if (err) { return next(err); }
//Respond to request indicating the user was created
res.json({ success: true });
});
});
}
At the moment you are not returning the right status code in your response, you could try this:
Replace:
return res.err("Please enter in email and password");
With
return res.status(422).send({error: "Please enter in email and password"})
And replace:
return res.err( 'Email is in use' );
With:
return res.status(422).send({ error: "Email is in use" });
This will send back the required status code in the http response.
Also consider only using single or double quotes in your code for consistency.

JSON Web Tokens - attach the token to requests

I am trying to set up an authentication via token for my web app. I am using nodejs for the back end and the jwt-simple module to encode/decode the tokens.
I manage to create and handle the tokens from the server to the client. However I struggle to handle the token from the client to the server.
For example, I have a page called profile for which I handle the requests the following way:
app.get('/profile', [bodyParser(), jwtauth], function(req, res) {
res.render('profile.ejs', {
user : req.user // get the user out of session and pass to template
});
});
Where jwtauth is the following:
var jwt = require('jwt-simple');
var User = require('../server/models/user');
 
module.exports = function(req, res, next) {
var token = (req.user && req.user.access_token) || (req.body && req.body.access_token) || (req.query && req.query.access_token) || req.headers['x-access-token'];
if (!token)
return next('invalid or no token');
try {
var decoded = jwt.decode(token, app.get('jwtTokenSecret'));
if (decoded.exp <= Date.now())
return res.end('Access token has expired', 400);
User.findOne({ _id: decoded.id }, function(err, user) {
req.user = user;
});
return next();
} catch (err) {
return next('couldn\'t decode token');
}
};
On the client side I attached the token once the user is logged in the following way:
$(document).ready(function() {
var token = __token;
if (token) {
$.ajaxSetup({
headers: {
'x-access-token': token
}
});
}
});
But if I try to get the url '/profile' in my browser there is no 'x-access-token' in the headers and I get the 'invalid or no token' message.
How can I set the token on the client side so that it is attached to every request to my server?
Many thanks
What are you seeing when you console.log(req.headers) in your jwtauth middleware? Are you deifning $.ajaxSetup more than once? See this post