How to pass extra data and check if token is valid with JWT - node.js

I just started a project where I have to use Node + few things related to it and I feel a little confused!
I use JWT for authentication, particularly I created my project like this:
api
|---teams
|----teams.controller.js
|----teams.router.js
|----teams.service.js
|---users (same as team)
auth
|---token_validation.js
other things
|---other things
I use token_validation.js for JWT to validate user while login and seems it work (verified with Postman)
const jwt = require("jsonwebtoken");
module.exports = {
checkToken: (req, res, next) => {
let token = req.get("authorization");
if (token) {
// Remove Bearer from string
token = token.slice(7);
jwt.verify(token, process.env.JWT_KEY, (err, decoded) => {
if (err) {
console.log("err: " + err);
return res.json({
success: 0,
message: "Invalid Token..."
});
} else {
req.decoded = decoded;
next();
}
});
} else {
// other code
}
}
};
I need to insert a new team in DB (MariaDB) and user can create a new team after login. My problem is that while using Session in Java for e.g. I can easly set extras like username of the logged in user and when I need to know what's the username of the logged in user is, I can take it from session
String username = (String) session.getAttribute("username");
I can't understand how to do the same with Node/JWT. What I need to do is, after login I need to save the user_id and when user crate a new team I need to send to DB the user_id with other data (if token still valid).
const {
create
} = require("./teams.service");
module.exports = {
createTeam: (req, res) => {
const body = req.body;
// here I need to check if token still valid
// if yes -> take user id and send it to DB with
// other data
create(body, (err, results) => {
if (err) { // if fails
// handle
}
return res.status(200).json({ // success
success: 1,
data: results
});
});
},
}
I thought I could add it in user.controller.js when user login:
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h",
user_id: get somehow //error
});
// other code
}
but it gives me an error, tells me like I can't add user_id to sign. Can anyone please tell me the right way to store and get this kind of data and use them when needed while user still have a valid token to stay logged in?

You are adding your data to the options, not the payload.
if (result) {
results.password = undefined;
results.user_id = XXXXXXXX //get somehow
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
...
}

Best option is to set it in localStorage. When you make a req to backend send it with headers, then in backend check if token is valid and send response with data that you want.

Related

Unable to get document using document.findOne()

I tried to get a document using document.findOne() but it's value is showing undefined .
Here is my code
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
const user= Student.findOne({srno:req.body.srno});
console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
I'm implementing session authentication using express-session. Here when I log the user it's showing schema and bunch of other stuff which I don't know(The error is too long) . user.srno is also showing as undefined. How can I fix it?
I tried using call-back function which gave me required document correctly. But I want the query to return the correct document and store it in user.
Using callback function
`app.post("/studentlogin",(req,res)=>
{
let password;
console.log("login page");
bcrypt.hash(req.body.password,saltRounds,(err,hash)=>
{
Student.findOne({srno:req.body.srno},(err,result)=>
{
console.log(result);
});
//console.log(user.srno);
if(req.body.srno==user.srno && hash==user.password)
{
session=req.username;
session.userid=req.body.srno;
res.redirect("/");
}
else{
console.log("invalid user");
res.redirect("/studentlogin");
}
});
})`
You need to wait the result from your query on the database before doing the next task like comparing your password, and looks like you just try to log in, you re not going to register a new one, so it's better to use the compare method in Bcrypt like this :
app.post("/studentlogin", async (req , res) => {
const {srno, password} = req.body // destructuring your request is better for visibility
try {
const user = await Student.findOne({srno: srno});//await the result before next step
console.log(user.srno) //you can check
if(!user) {
console.log("invalid user");
// your logic to tell not student found /wrong username or password, and/or redirect
}
const isMatch = await bcrypt.compare(password, user.password) //await the result and this method for comparing the request password and the user's password found
if(!isMatch) {
//your code to tell Wrong username or password
res.redirect("/studentlogin");
} else {
// your code to access to the login.
res.redirect("/");
}
} catch (err) {
console.log(err)
}
The error you are facing is because you are not using async await in your code. use async in your function definition then use await where you are searching the database.
const someFunction = async(req,res)=>{
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
Your code should look like this.
app.post("/studentlogin", async(req,res)=> {
// your code
const user=await Student.findOne({srno:req.body.srno});
// your code
}
console.log(user) to verify.
Hope it helps.

How do I get a value from Postgres, in NodeJS?

I'm now trying to build the user authentication logic of a website. Now I should check, when a user tries to log in, does he have a registered email/password already. But I cannot just simply get the field's value from the DB, as a string.
In the database, I have 6 fields (isSuperuser, fullName, institution, password, email, approved). For the authentication, the unfinished method is here:
router.post("/login", async (req, res, next)=> {
const email = req.body.email;
const data = await client.query(`SELECT * FROM user_table WHERE email= $1;`, [email])
const arr = data.rows
//const arr = data.rows;
.then(user=> {
if(arr==null || arr== undefined || arr.length==0){
return res.status(401).json({
message: "Login authentication failed!"
})
}
})
})
My problem is, that, when I check, if the email, provided at login, already exists, I should simply compare it (req.body.email) with the value(s) of the email field in the database. But I did not find any solution, how to just get a string, as a result for the query. The const arr gives an array, from which I cannot get the value of the email key. So far, this code might works (though ugly as hell), but when it comes to password compare, I will bleed.
If I try
client.query("SELECT password FROM user_table WHERE email= $1;", [email])
it only gives back an empty array.
What do I do wrong? Any solution, please?
Iam not sure about PostgreSql but I know sql so give it a try;
router.post("/login", async (req, res, next) => {
const { email } = req.body;
const data = await client.query(`SELECT * FROM user_table WHERE email= ${email}`).then((result) => {
return result
})
if (!data) { // OR if data is an array then use "data.length == 0"
return res.status(401).json({
success: false,
message: "Login authentication failed!"
})
}
})

I need to create a rest API in node that calls another API

I need to create a REST API in my node app, that GET data from an external API - https://newsapi.org/v2/top-headlines?category=%7Bcategoryname%7D&apiKey=APIKEY
The condition is that this rest API should contain id of the user in DB.
Only when we trigger an API with valid userID, it should return response as the data coming from external API.
otherwise show error
Can you help me build a function that would do so?
I am using mongoDB
I am writing few snippets of code i wrote to accomplish this, but i am pretty bad at it. So any help on this will be highly appreciated:
app.js
router.get('/api/Users/news/:id', controller.newsget);
router.get('/api/Users/news/:id', (req, res) => {
const id = req.params.id;
for (let i = 0; i <User.length; i++) {
let user = User[i]
if (user.id === id) {
axios
.get('http://newsapi.org/v2/top-headlines?country=in&category=general&apiKey=36f3e29b704f41339af8439dc1228334')
.then(response => {
let userData = response.data;
res.send(userData);})
}
}
});
controller.js
exports.newsget = (req, res)=>{
if(!req.body){
return res
.status(400)
.send({ message : "Data to update can not be empty"})
}
const id = req.params.id;
User.findByIdAndUpdate(id, req.body, { useFindAndModify: false})
.then(data => {
if(!data){
res.status(404).send({ message : `Cannot Update user with ${id}. Maybe user not found!`})
}else{
res.send(data)
}
})
.catch(err =>{
res.status(500).send({ message : "Error Update user information"})
})
}
I have very little clue on the approach, but i badly need assistance. Please help
I have tried mimicking some online functions to search the user and then try to fetch data from external API if the user's ID was present in my DB. But it failed
First of all, you are writing two GET methods for same route, from what I am being concluding that, the first route should be POST according to what I am suspecting to be your functionality is depicted as follows
router.post('/api/Users/news/:id', controller.newsget);
router.get('/api/Users/news/:id', (req, res) => {
const id = req.params.id;
for (let i = 0; i <User.length; i++) {
let user = User[i]
if (user.id === id) {
axios
.get('http://newsapi.org/v2/top-headlines?country=in&category=general&apiKey=36f3e29b704f41339af8439dc1228334')
.then(response => {
let userData = response.data;
res.send(userData);})
}
}
});
Also if you are picking the logged in user, use req.user.id

NodeJS express basicAuth - how to pass username to the route function?

I've got a working node app where I need to connect to different DBs based on what user is connecting to the app via basicAuth.
Here's a sample:
// Authenticating function
var sgAuth = express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback(null, false);
} else {
callback(null, config.credentials.clients[user].password == pass);
}
});
// This function needs to know what user has authenticated
function putEvents(req, res) {
//How do I know what user authenticated in this request?
var authUser = ???;
var table = getUserTable(authUser);
...
}
app.post('/put', sgAuth, putEvents);
Storing username in sgAuth to some var surely won't work, because there can be many incoming connections from different users, so you can't guarantee that its the same user, right? Can this info be retrieved from the request header somehow?
The basicAuth() middleware will set req.user and req.remoteUser once authorized.
Though, note that the 2nd argument to the callback is expected to be the user, not simply an authorized boolean. But, it can be any truthy value you desire, including the user name.
callback(null, config.credentials.clients[user].password == pass ? user : null);
After that, you should be able to retrieve it with:
var authUser = req.user;
Note that: basicAuth is deprecated
Here the code:
app.use(express.basicAuth(function(user, pass, callback){
if(config.credentials.clients[user] === undefined) {
callback('user not found!!!');
} else {
if(config.credentials.clients[user].password === pass) {
callback(null, config.credentials.clients[user]);
} else {
callback('wrong pass!!!');
}
}
});
app.post('/put', function putEvents(req, res) {
console.log(req.user.name)
res.end();
});

authentication using node.js and mongodb

Guys I am trying to get myself authenticated and for this I am using node.js and mongo DB.But the thing is that after registarion the user is not able to authenticate himself.Here is my snippet
app.post('/login',function(req,res){
ContactProvider.findAll(function(error, posts) {
var aut = req.body;
if (aut.user == posts.user && aut.pass == posts.pass) {
req.session.name = {name:aut.user};
res.redirect('/home');
} else {
res.send('Bad user/pass');
}
});
});
Below is my snippet for registering the user
app.post('/register',function(req, res) {
var post=req.body;
if(post.pass!=post.cpass) {
res.send("Error:Password doesnt match");
} else {
ContactProvider.save({
user: req.param('user'),
pass: req.param('pass'),
cpass: req.param('cpass'),
email: req.param('email')
}, function(error, docs) {
res.redirect('/');
});
}
});
The ContactProvider is the one below where post provider is a different file where all the mongoose things happen
var ContactProvider = require('./PostProvider').ContactProvider;
var ContactProvider= new ContactProvider();
This is the finone query in the postprovider file
ContactProvider.prototype.findone = function(name,pass, callback) {
Post.findOne({name:name},{pass:pass}, function (err, post) {
callback(null, post);
});
};
Something's seriously wrong with your code ( why you use name posts for an array of ContactProvider? ). You have to search for ContactProvider based on username and password. Something like this:
app.post('/login',function(req,res){
var aut = req.body;
ContactProvider.findOne(
{
user: aut.user,
pass: aut.pass
},
function(err, usr) {
if (error || !usr) {
res.send('Bad user/pass');
} else {
// we have a user, authenticate!
req.session.name = {name:aut.user};
res.redirect('/home');
}
}
);
});
SIDE NOTE: This is a very simple way of authenticating users, but it is not secure at all. You should read more about authentication and security in the internet. Very useful knowledge indeed.
EDIT: There's also an issue with your registration. Your data is stored in post variable, so use it on ContactProvider as well:
// some other code
ContactProvider.save({
user: post.user,
pass: post.pass,
cpass: post.cpass, // no need to store the same thing twice
email: post.email

Resources