I am trying to use passport js for authentication in my local mysql database. I am using postman extension to test the application.
I am sending two fields i.e. username and password for authentication. When any one of the field is blank then response is shown in json format as
{
"message": "Missing credentials",
"user": false
}
But when I pass values for both the fields I get 500 internal server error.
error: Sending 500 ("Server Error") response:
TypeError: Cannot read property 'message' of undefined
at d:\Test\api\controllers\AuthController.js:25:23
at Strategy.strategy.error (d:\Test\node_modules\passport\lib\middleware\authenticate.js:333:18)
at Strategy.authenticate (d:\Test\node_modules\passport-local\lib\strategy.js:94:17)
at attempt (d:\Test\node_modules\passport\lib\middleware\authenticate.js:341:16)
at authenticate (d:\Test\node_modules\passport\lib\middleware\authenticate.js:342:7)
at Object.module.exports.login (d:\Test\api\controllers\AuthController.js:37:7)
at bound (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\lodash\dist\lodash.js:729:21)
at routeTargetFnWrapper (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:179:5)
at callbacks (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:164:37)
at param (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:138:11)
at pass (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:145:5)
at nextRoute (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:100:7)
at callbacks (C:\Users*\AppData\Roaming\npm\node_modules\sails\node_modules\express\lib\router\index.js:167:11)
at C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:187:7
at alwaysAllow (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\hooks\policies\index.js:207:11)
at routeTargetFnWrapper (C:\Users*\AppData\Roaming\npm\node_modules\sails\lib\router\bind.js:179:5) [TypeError: Cannot read property 'message' of undefined]**
Below is my AuthController
var passport=require('passport');
login:function(req,res){
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message:info.message,
user: user
});
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message:"User Loged In",//info.message,
user: user
});
});
})(req, res);
}
};
I am using the below model for testing
module.exports = {
tableName: 'users',
connection:'TestDB',
autoCreatedAt:false,
autoUpdatedAt:false,
attributes: {
username:{
type:'string',
required:true
},
password:{
type:'string',
required:true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
}
};
The table which contains the username and password also has other fields like country. Is there any way I can authenticate it using passport.
did you do the sixth step of this link
module.exports.http = {
middleware: {
passportInit : require('passport').initialize(),
passportSession : require('passport').session(),
order: [
'startRequestTimer',
'cookieParser',
'session',
'passportInit',
'passportSession',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'router',
'www',
'favicon',
'404',
'500'
],
}
};
maybe you want to see sails-hook-sanpassport, is easy and fast
Related
this is my login post method in the reactjs frontend
const login = () => {
Axios.post("http://localhost:3001/api/users/login", {
email: values.email,
password: values.password,
}).then((response) => {
console.log(response.data);
}).catch(err =>{
console.log(err)
})
};
this is my expressjs server side, here i have login post method for reactjs frontend, where iam on response i want to send token to set in cookie whenever user post on login method, below is code for login post method
login: (req, res) => {
const body = req.body;
console.log("req.body :", req.body);
getUserByEmail(body.email, (err, results) => {
console.log("results :", results);
if (err) {
console.log(err);
return;
}
if (!results) {
res.json({
status: "failure",
msg: "Invalid email or password",
});
}
const result = compareSync(body.password, results.password);
const SECRET_KEY = "xyz123";
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, SECRET_KEY, {
expiresIn: "1h",
});
// console.log(res)
res.cookie("token", jsontoken, {
httpOnly: true,
domain: "http://localhost:3000/login",
});
return res.json({
status: "Success",
msg: "login Successfully",
token: jsontoken,
});
} else {
return res.json({
status: "failure",
msg: "Invalid email or password",
});
}
});
},
What you could do, that is actually more secure, is tell the browser using headers on the response to create a cookie.
There is a header in HTTP called Set-Cookie, which is responsible to do just that, you can read more about it here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie.
The way you add it to your request on express is by calling the res.cookie function on your express request handler. I would suggest telling the cookie to be httpOnly in order for it to not be accessible through JS code, this is just a way to avoid XSS attacks.
Here you have an example to how to achieve that:
res.cookie('token', jsontoken, { httpOnly: true });
Then in order to access the cookie, you would need to use the cookieParser middleware which is responsible in putting all the cookies the client sent in req.cookies.
You use it this way:
app.use(express.cookieParser());
I am using mysql with nodejs. I am getting "Error: failed to serialize user into session". When I console.log user in serializeuser function it prints "serialize [object Object]" and in "local-login" strategy it prints RowDataPacket as shown below.
RowDataPacket {
Patient_id: 2,
fname: 'xxx',
mname: 'yyy',
lname: 'zzz',
Email: 'xxx#yyy.com',
pass: '$2b$10$ycZI4SLTJEihxKDHpCXwcOhkmBiOKzmMqFyuEOgXa0KuXYupgaMeG',
Contact: '090078601',
Gender: 'Male',
dateofbirth: 1111-01-13T19:31:48.000Z,
Blood_group: null
}
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
console.log(`serialize ${user}`)
done(null, user.patient_id)
})
// used to deserialize the user
passport.deserializeUser(function(id, done) {
// connection.connect()
connection.query("SELECT * FROM PATIENT WHERE PATIENT_ID = ? ",[id], function(err, rows){
done(err, rows[0])
})
// connection.end()
})
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// connection.connect()
connection.query("SELECT * FROM PATIENT WHERE EMAIL = ?",[email],function(err,rows){
if (err)
return done(err)
if (!rows.length) {
return done(null, false, req.flash('error', 'No user found.')) // req.flash is the way to set flashdata using connect-flash
}
bcrypt.compare(password, rows[0].pass, function(err, result) {
if(!result)
{
return done(null, false, req.flash('error', 'Oops! Wrong password.'))
}
// console.log(rows[0])
});
return done(null, rows[0])
})
// connection.end()
}
))
my post login look like this
router.post('/patient/login', ensureGuest, passport.authenticate('local-login', {
successRedirect : '/home', // redirect to the secure profile section
failureRedirect : 'login', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})
);
don't suggest to use session:false while authenticating in post method
The type of object being returned by the sql query was causing the problem, serialize and deserialize accepts json object so I just added stringifyObjects option in my connection configs so that sql query returns json objects and not the default type of object which it usually returns.
module.exports = {
'connection': {
'host': 'localhost',
'user': 'root',
'password': 'fast',
'database': 'hms',
'stringifyObjects': 'Stringify'
}
};
I have a nuxt app with express and mySQL.
Problem : I am unable to display the express res.send() custom error message on the vue side
Let's pretend I want to display infos of one single user.
Here is my back-end code :
// Find a single User with a userId
exports.findOne = (req, res) => {
User.findById(req.params.userId, (err, data) => {
if (err) {
if (err.kind === 'not_found') {
res.status(404).send({
message: `Not found User with id ${req.params.userId}.`
})
} else {
res.status(500).send({
message: 'Error retrieving User with id ' + req.params.userId
})
}
} else { res.send(data) }
})
}
And here is the Vue part
<script>
import axios from 'axios'
import appNavbar from '~/components/appNavbar.vue'
export default {
components: {
appNavbar
},
data () {
return {
userId: '',
userData: '',
errorMsg: ''
}
},
methods: {
fetchUser (evt) {
evt.preventDefault()
return axios.get('/api/users/' + this.userId)
.then((res) => {
this.userData = res.data
})
.catch((err) => {
this.errorMsg = err.toJSON()
})
}
}
}
</script>
When I give the id of a non-existing user, I want to be able to get the custom error message written in the back, and display it in the front
BUT I only get this JSON
{ "message": "Request failed with status code 404", "name": "Error" }
Does anyone have a clue ?
Thanks !
This error maybe occours because you are not setting the host when you call teh API at line:
return axios.get('/api/users/' + this.userId)
404 error is because browser not found this endpoint.
In this case, I recommend you try to call this endpoint in another tool (like Postman) and certify if your API is responding correctly.
After that, fix your call to endpoint, maybe it will be somwthing like the code bellow and try again:
return axios.get(`${your host here}/api/users/ + ${this.userId}`)
EDIT : SOLUTION FOUND
Answer found here: https://github.com/axios/axios/issues/960#issuecomment-309287911
On the vue part, the catch should return err.response, and not just err.
So in order to display your custom error message, it should be like this:
.catch((err) => {
this.errorMsg = err.response
I am using nodejs and express to connect my local mysql db, everythings look working well except no response when Iam trying to test the API in postman.
here is my code in server.js
//add sales
app.post('/sales',(req, res) => {
var POST_SALES_QUERY = {
username: req.body.username,
password: req.body.password,
fullname: req.body.fullname
}
if (!POST_SALES_QUERY) {
return res.status(400).send({ err: true, message: 'Please username' });
}
dbConn.query("INSERT INTO user_tbl SET ?", (POST_SALES_QUERY, err, results) => {
if(err){
console.log(err);
} else {
return res.send(JSON.stringify({"status": 200, "err" : null, "response": results}));
}
});
});
and in Postman, I get this:
any idea what the problem appears here?
app.post('/sales',(req, res) => {
var POST_SALES_QUERY = {
username: req.body.username,
password: req.body.password,
fullname: req.body.fullname
}
if (!POST_SALES_QUERY) {
return res.status(400).send({ err: true, message: 'Please username' });
}
let query = `INSERT INTO user_tbl (username, password, fullname) VALUES ('${POST_SALES_QUERY.username}','${POST_SALES_QUERY.password}','${POST_SALES_QUERY.fullname}')`;
dbConn.query(query,function(err,results) {
if(err){
console.log(err);
} else {
return res.status(200).json({"status": 200,"err": null,"response": results});
}
});
});
You need to tell express to treat the body as json, by calling the following codes:
app.use(express.json())
As per the documentation:
This is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser.
Has anyone experienced extending the built-in model "user" in StrongLoop via Client?
The thing is, I can't skip the verification for the newly created clients. I have declared the Client with the option "emailVerificationRequired": false, but still I can't log in.
Error:
error: Object code: "LOGIN_FAILED_EMAIL_NOT_VERIFIED" message: "login
failed as the email has not been verified" name: "Error" stack:
"Error: login failed as the email has not been verified↵ at
C:\xampp\htdocs\loopback-getting-started\node_modules\loopback\common\models\user.js:248:21↵
at
C:\xampp\htdocs\loopback-getting-started\node_modules\loopback\common\models\user.js:312:9"
status: 401 statusCode: 401
If you don't want email verification PUT below code in
model-config.json
"user": {
"dataSource": "YOUR DATASOURCE",
"public": true,
"options": {
"emailVerificationRequired": false
},
"$promise": {},
"$resolved": true}
And other thing is, you manually stop verification doing below logic.
For example if users created by Admin.
user.beforeRemote('create' ,function(ctx, modelInstance, next)
{
if(ctx.req.query.key == "admin") // if users created by Admin.
{
ctx.args.data.emailVerified = 1;
}
next();
});
IN afterRemote
user.afterRemote('create', function(context, user, next) {
if(!user.emailVerified)
{
console.log('> user.afterRemote triggered');
var options = {
type: 'email',
to: user.email,
from: 'youremail,
subject: 'Thanks for registering.',
template: path.resolve(__dirname, '../../server/views/verify.ejs'),
redirect: '/verified',
user: user
};
user.verify(options, function(err, response) {
if (err) return next(err);
context.res.render('response', {
title: 'Signed up successfully',
content: 'Please check your email and click on the verification link ' +
'before logging in.',
redirectTo: '/',
redirectToLinkText: 'Log in'
});
});
}
else
{
next();
}
});