I am getting an error trying to pass the headers value from Postman to a NodeJS service.
I created a method to handle the request object called ‘data.headers.token’ that is supposed to pass the Postman headers value to a variable I created called ‘token’.
var token = typeof(data.headers.token) == 'string' ? data.headers.token : false;
What I am trying to do is to get the information of a user using a token ID that must match the user’s phone number. The required request must have the token ID in the headers sent from Postman, which must match what is stored in JSON on the Node server.
It does not appear that the ‘data.headers.token’ object is recognized. The error is detected in the method I created called ‘handlers._users.get’.
Here is the code from the source (created as a file I called handlers.js):
/*
These are the request handlers
*/
//Dependencies
var _data = require('./data');
var helpers = require('./helpers');
var config = require('./config');
//Define handlers
var handlers = {};
/*// ping handler
handlers.ping = function(data,callback) {
callback(200);
}; */
//users handler
handlers.users = function(data,callback) {
var acceptableMethods = ['post','get','put','delete'];
if(acceptableMethods.indexOf(data.method) > -1) {
handlers._users[data.method](data,callback);
} else {
callback(405);
}
};
//Container for the users submethods
handlers._users = {};
//Users post
//required data:firstName, lastName, phone, password, tosAgreement
//optional data: None
handlers._users.post = function(data,callback){
//check all required fields are filled out
var firstName = typeof(data.payload.firstName) == 'string' && data.payload.firstName.trim().length > 0 ? data.payload.firstName.trim() : false;
var lastName = typeof(data.payload.lastName) == 'string' && data.payload.lastName.trim().length > 0 ? data.payload.lastName.trim() : false;
var phone = typeof(data.payload.phone) == 'string' && data.payload.phone.trim().length == 10 ? data.payload.phone.trim() : false;
var password = typeof(data.payload.password) == 'string' && data.payload.password.trim().length > 0 ? data.payload.password.trim() : false;
var tosAgreement = typeof(data.payload.tosAgreement) == 'boolean' && data.payload.tosAgreement == true ? true : false;
if(firstName && lastName && phone && password && tosAgreement) {
//make sure that the user does not already exist
_data.read('users',phone,function(err,data){
if(err) {
//hash the password
var hashedPassword = helpers.hash(password);
//create the user object
if(hashedPassword) {
var userObject = {
'firstName' : firstName,
'lastName' : lastName,
'phone' : phone,
'hashedPassword' : hashedPassword,
'tosAgreement' : true
};
//store the user
_data.create('users',phone,userObject,function(err){
if(!err) {
callback(200);
} else {
console.log(err);
callback(500,{'Error' : 'Could not create the new user'});
}
});
} else {
callback(500,{'Error' : 'Could not hash the user's password'});
}
} else {
//user already exists
callback(400,{'Error' : 'A user with that phone number already exists'});
}
});
} else {
callback(400,{'Error':'Missing required fields'});
}
};
//Users get
//Required data: phone
//Optional data: none
//only let an authenticated user access their object. Do not let them access other people's data.
handlers._users.get = function(data,callback){
//check that the phone number provided is valid
var phone = typeof(data.queryStringObject.phone) == 'string' && data.queryStringObject.phone.trim().length == 10 ? data.queryStringObject.phone.trim() : false;
if(phone){
//get the token from the headers
var token = typeof(data.headers.token) == 'string' ? data.headers.token : false;
//var token = (data && data.headers && typeof data.headers.token == 'string') ? data.headers.token : false;
//verify that the given token is valid for the phone number
handlers._tokens.verifyToken(token,phone,function(tokenIsValid){
if(tokenIsValid) {
//lookup the user
_data.read('users',phone,function(err,data){
if(!err && data) {
//remove the hashed password from the user object before returning it to the requestor
delete data.hashedPassword;
callback(200,data);
} else {
callback(404);
}
});
} else {
callback(403,{'Error':'Missing required token in header or token is invalid'});
}
});
} else {
callback(400,{'Error' : 'Missing Required Field'});
}
};
//Users put
//Required data: phone
//Optional data: firstName, lastName, password (at least one must be specified)
//only let an authenticated user update their own object. Do not let them update anyone elses.
handlers._users.put = function(data,callback){
//check for the required field
var phone = typeof(data.payload.phone) == 'string' && data.payload.phone.trim().length == 10 ? data.payload.phone.trim() : false;
//check for the optional fields
var firstName = typeof(data.payload.firstName) == 'string' && data.payload.firstName.trim().length > 0 ? data.payload.firstName.trim() : false;
var lastName = typeof(data.payload.lastName) == 'string' && data.payload.lastName.trim().length > 0 ? data.payload.lastName.trim() : false;
var password = typeof(data.payload.password) == 'string' && data.payload.password.trim().length > 0 ? data.payload.password.trim() : false;
//error if the phone is invalid
if(phone) {
//error if nothing is sent to update
if(firstName || lastName || password) {
//get the token from the headers
var token = typeof(data.headers.token) == 'string' ? data.headers.token : false;
//verify that the given token is valid for the phone number
handlers._tokens.verifyToken(token,phone,function(tokenIsValid){
if(tokenIsValid) {
//lookup user
_data.read('users',phone,function(err,userData){
if(!err && userData) {
//update the fields necessary
if(firstName){
userData.firstName = firstName;
}
if(lastName){
userData.lastName = lastName;
}
if(password){
userData.hashedPassword = helpers.hash(password);
}
//store the new updates
_data.update('users',phone,userData,function(err){
if(!err){
callback(200);
} else {
console.log(err);
callback(500,{'Error' : 'Could not update the user'});
}
});
} else {
callback(400,{'Error' : 'The specified user does not exist'});
}
});
} else {
callback(403,{'Error':'Missing required token in header or token is invalid'});
}
});
} else {
callback(400,{'Error' : 'Missing fields to update'});
}
} else {
callback(400,{'Error' : 'Missing required field'});
}
};
//Users delete
//Required field: phone
//only require an authenticated user delete their object. Do not let anyone else.
//delete or clean up any other data files associated with this user
handlers._users.delete = function(data,callback){
//check the phone number is valid
var phone = typeof(data.queryStringObject.phone) == 'string' && data.queryStringObject.phone.trim().length == 10 ? data.queryStringObject.phone.trim() : false;
if(phone){
//get the token from the headers
var token = typeof(data.headers.token) == 'string' ? data.headers.token : false;
//verify that the given token is valid for the phone number
handlers._tokens.verifyToken(token,phone,function(tokenIsValid){
if(tokenIsValid) {
//lookup the user
_data.read('users',phone,function(err,data){
if(!err && data) {
_data.delete('users',phone,function(err,data){
if(!err) {
callback(200);
} else {
callback(500,{'Error':'Could not delete the specified user'});
}
});
} else {
callback(400,{'Error':'Could not find the specified user'});
}
});
} else {
callback(403,{'Error':'Missing required token in header or token is invalid'});
}
});
} else {
callback(400,{'Error' : 'Missing Required Field'});
}
};
//Tokens handler
handlers.tokens = function(data,callback) {
var acceptableMethods = ['post','get','put','delete'];
if(acceptableMethods.indexOf(data.method) > -1) {
handlers._tokens[data.method](data,callback);
} else {
callback(405);
}
};
//Container for all the tokens
handlers._tokens = {};
//Tokens - post
//Required data: phone,password
//Optional: none
handlers._tokens.post = function(data,callback){
var phone = typeof(data.payload.phone) == 'string' && data.payload.phone.trim().length == 10 ? data.payload.phone.trim() : false;
var password = typeof(data.payload.password) == 'string' && data.payload.password.trim().length > 0 ? data.payload.password.trim() : false;
if(phone && password) {
//lookup the user that matches that phone number
_data.read('users',phone,function(err,userData){
if(!err && userData) {
//hash the sent password and compare it to the password stored in user object
var hashedPassword = helpers.hash(password);
if(hashedPassword == userData.hashedPassword) {
//if valid, create a new token with a random name. Set expiration date 1 hour in the future
var tokenId = helpers.createRandomString(20); //20 character token string
var expires = Date.now() + 1000 * 60 * 60;
var tokenObject = {
'phone' : phone,
'id' : tokenId,
'expires' : expires
};
//store the token
_data.create('tokens',tokenId,tokenObject,function(err){
if(!err){
callback(200,tokenObject);
} else {
callback(500,{'Error':'Could not create the new token'});
}
});
} else {
callback(400,{'Error':'Password did not match the stored password'});
}
} else {
callback(400,{'Error':'Could not find the specified user'});
}
});
} else {
callback(400,{'Error':'Missing required fields'});
}
};
//Tokens - get
//Required data: id
//Optional data: none
handlers._tokens.get = function(data,callback){
//check id sent is valid
var id = typeof(data.queryStringObject.id) == 'string' && data.queryStringObject.id.trim().length == 20 ? data.queryStringObject.id.trim() : false;
if(id){
//lookup the user
_data.read('tokens',id,function(err,tokenData){
if(!err && data) {
callback(200,tokenData);
} else {
callback(404);
}
});
} else {
callback(400,{'Error' : 'Missing Required Field'});
}
};
//Tokens - put
//Required: id, extend
//Optional data: none
handlers._tokens.put = function(data,callback){
var id = typeof(data.payload.id) == 'string' && data.payload.id.trim().length == 20 ? data.payload.id.trim() : false;
var extend = typeof(data.payload.extend) == 'boolean' && data.payload.extend == true ? true : false;
if(id && extend) {
//lookup the token
_data.read('tokens',id,function(err,tokenData){
if(!err && tokenData) {
//check to make sure token is not expired
if(tokenData.expires>Date.now()){
//set expiration an hour from now
tokenData.expires = Date.now() + 1000 * 60 * 60;
//store the new updates
_data.update('tokens',id,tokenData,function(err){
if(!err){
callback(200);
} else {
callback(500,{'Error':'Could not update the token's expiration'});
}
});
} else {
callback(400,{'Error':'Token has already expired and cannot be extended'});
}
} else {
callback(400,{'Error':'Specified token does not exist'});
}
});
} else {
callback(400,{'Error':'Missing required field(s) are invalid'});
}
};
//Tokens - delete
//Required data: id
//Optional data: none
handlers._tokens.delete = function(data,callback){
//check that the id is valid
var id = typeof(data.queryStringObject.id) == 'string' && data.queryStringObject.id.trim().length == 20 ? data.queryStringObject.id.trim() : false;
if(id){
//lookup the token
_data.read('tokens',id,function(err,data){
if(!err && data) {
_data.delete('tokens',id,function(err,data){
if(!err) {
callback(200);
} else {
callback(500,{'Error':'Could not delete the specified token'});
}
});
} else {
callback(400,{'Error':'Could not find the specified token'});
}
});
} else {
callback(400,{'Error' : 'Missing Required Field'});
}
};
//Verify if a given token id is currently valid for a given user
handlers._tokens.verifyToken = function(id,phone,callback){
//lookup the token
_data.read('tokens',id,function(err,tokenData){
if(!err && tokenData){
//check that the token is for the given user and has not expired
if(tokenData.phone == phone && tokenData.expires > Date.now()){
callback(true);
} else {
callback(false);
}
} else {
callback(false);
}
});
};
//Not found handler
handlers.notfound = function(data,callback) {
callback(404);
};
//Export the module
module.exports = handlers;
Here is a snippet of the error message I get from the server console:
D:appServiceTokensServicelibhandlers.js:96
var token = typeof(data.headers.token) == 'string' ? data.headers.token : false;
^
TypeError: Cannot read properties of undefined (reading 'token')