Missing claims in payload of jwt token - express

As part of my login endpoint I return a generated token using the 'generateToken' function. The payload contains an object of claims(user.id and user.role). However when I log in and check the returned token I do not see any of the claims; just the 'created' and 'expires' values.
Login endpoint
async function findUserById(req, res){
let { email, password } = req.body;
try {
const user = await db.query("SELECT * FROM user_account WHERE email = $1", [email]);
if(!user.rows.length){
return res.status(401).json("Invalid crendential")
}
const validPassword = await bcrypt.compareSync(password, user.rows[0].password)
if(!validPassword){
return res.status(401).json("Invalid credential");
}
const token = await generateToken(user);
res.status(200).json({ user, email: user.email, token})
} catch (error) {
res.status(500).json({error: error.message})
}
}
generateToken function
const jwt = require("jsonwebtoken");
const secret = require("../config/secrets");
function generateToken(user){
const payload = {
subject: user.id,
role: user.role
};
const options = {
expiresIn: "30d"
};
return jwt.sign(payload, secret.jwtSecret, options)
}
module.exports = {generateToken};

Related

authorization header undefined, empty

Can you explain what I'm doing wrong, I don't understand why my header is empty. Login is working but when I trigger the me query it's not working, not authenticated appear and if I console log this it's undefined.
How to keep the user logged, and be able to acces the data ?
Here is my code, if you know what's wrong.
Thanks
import * as dotenv from 'dotenv';
dotenv.config();
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { PrismaClient } from '#prisma/client';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
const JWT_SECRET = 'abc123';
const typeDefs = `
type User {
id: ID
username: String
}
type Query {
me: User
}
type Mutation {
signup(username: String!, password: String!): User
login(username: String!, password: String!): User
}
`;
const resolvers = {
Query: {
async me(_, __, context) {
// Check if the request has a valid JWT
const auth = context.req.headers.authorization;
if (!auth) {
throw new Error('Not authenticated');
}
// Get the user ID from the JWT
const token = auth.split('Bearer ')[1];
const { userId } = jwt.verify(token, JWT_SECRET);
// Retrieve the user from the database
return context.prisma.user({ id: userId });
},
},
Mutation: {
async signup(_, { username, password }, context) {
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Create a new user in the database
const user = await context.prisma.user.create({
data: {
username,
password: hashedPassword,
},
});
// Create a JWT for the new user
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
return { token, ...user };
},
async login(_, { username, password }, context) {
// Retrieve the user from the database
const user = await context.prisma.user.findUnique({
where: {
username: username,
},
});
if (!user) {
throw new Error('Invalid login');
}
// Compare the provided password with the hashed password
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
throw new Error('Invalid login');
}
// Create a JWT for the user
const token = jwt.sign({ userId: user.id }, JWT_SECRET);
return { ...user, token };
},
},
};
const main = async () => {
const app = express();
const prisma = new PrismaClient();
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => ({ req, prisma }),
});
await server.start();
server.applyMiddleware({ app });
app.listen(4000, () =>
console.log(`GraphQL server running on http://localhost:4000`)
);
};
main().catch((err) => {
console.error(err);
});

Getting error in MERN stack Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am new to MERN. I was using this code below . I followed a youtube tutorial and it was working fine for me for 4 to 5 days but now suddenly it has stopped working. I didn't change anything. I am not able to login, logout or even fetch data. My postman is giving positive results using these api but it won't work on my code. I want to remind you guys again, it was working fine for 4 to 5 days.
const User = require("../model/user");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const signup = async (req, res, next) => {
const { fname, lname, email, password, role, phone } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ email: email });
} catch (err) {
console.log(err);
}
if (existingUser) {
return res.status(400).json({ message: "user already exists" });
}
const hashedPassword = bcrypt.hashSync(password);
const user = new User({
fname,
lname,
email,
password: hashedPassword,
phone,
role,
});
try {
await user.save();
} catch (err) {
console.log(err);
}
return res.status(201).json({ message: user });
};
const login = async (req, res, next) => {
const { email, password } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ email: email });
} catch (err) {
console.log(err);
}
if (!existingUser) {
return res
.status(400)
.json({ message: "user doesn't exist. Please signup" });
}
const isPasswordCorrect = bcrypt.compareSync(password, existingUser.password);
if (!isPasswordCorrect) {
return res.status(401).json({ message: "invalid email or password" });
}
const token = jwt.sign({ id: existingUser._id }, "change1122", {
expiresIn: "1h",
});
res.cookie(String(existingUser._id), token, {
path: "/",
expires: new Date(Date.now() + 1000 * 3600),
httpOnly: true,
sameSite: "lax",
});
return res
.status(200)
.json({ message: "user logged in sucessfully", user: existingUser, token });
};
const verifyToken = (req, res, next) => {
const cookies = req.headers.cookie;
const token = cookies.split("=")[1];
if (!token) {
res.status(404).json({ message: "no token found" });
}
jwt.verify(String(token), "change1122", (err, user) => {
if (err) {
return res.status(404).json({ message: "invalid token" });
}
req.id = user.id;
});
next();
};
const getUser = async (req, res, next) => {
const id = req.id;
let user;
try {
user = await User.findById(id, "-password");
} catch (err) {
console.log(err);
}
if (!user) {
res.status(404).json({ message: "user not found with the id" });
}
return res.status(200).json({ user });
};
const logout = async (req, res, next) => {
const cookies = req.headers.cookie;
console.log(cookies);
const token = cookies.split("=")[1];
if (!token) {
res.status(404).json({ message: "no token found" });
}
const user = req.id;
res.clearCookie(`${user}`);
req.cookies[`${user}`] = "";
return res.status(200).json({ message: "successfully logged out" });
};
exports.signup = signup;
exports.login = login;
exports.verifyToken = verifyToken;
exports.getUser = getUser;
exports.logout = logout;
Here is the error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:372:5) at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (E:\Reacct\pos\server\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (E:\Reacct\pos\server\node_modules\express\lib\response.js:174:12)
at ServerResponse.json (E:\Reacct\pos\server\node_modules\express\lib\response.js:278:15)
at getUser (E:\Reacct\pos\server\controller\user-controller.js:86:25)
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
[nodemon] app crashed - waiting for file changes before starting...
I think i have an issue with cookies or token, I am new so i don't understand it properly.

display data on page when user is auth, express , jwt, cookie-parser

I have simple application where user can register and login in his acc, now i want display user login on page, how i can get data from db about user that authinticated now
i also use mongodb and moongose as database
this register sistem
router.post('/register',async (req,res)=>{
const {login,mail,password} = req.body
bcrypt.hash(password, 10).then((hash) =>{
User({login:login,password:hash,mail:mail}).save()
})
res.redirect('/login')
})
this is login sistem
router.post('/',async (req,res)=>{
const {mail, password } = req.body
const user = req.body
console.log(user)
const isUserExist = await User.findOne({mail:mail})
const UserPwdCorrect = isUserExist.password
if(!isUserExist){
console.log('Логин гавно')
} else{
bcrypt.compare(password,UserPwdCorrect).then((match)=>{
if(!match){
console.log("Пароль говно")
} else{
const accessToken = createToken(user)
res.cookie("token",accessToken,{
maxAge:60*60*24*30*1000
})
res.redirect('/')
}
})
}
})
and this is what i did in jwt.js file
const {sign,verify} = require("jsonwebtoken")
const createToken = (user) =>{
const accessToken = sign({login: user.login, isAdmin:user.idAdmin,id:user.id},"jwt-secret")
return accessToken
}
const validateToken = (req,res,next) =>{
const accessToken = req.cookies["token"]
console.log(accessToken)
if(accessToken){
try {
const validtoken = verify(accessToken,"jwt-secret")
if(validtoken){
req.authenticated = true
return next()
} else{
return next()
}
} catch(err){
console.log(err)
}
}
}
Here's one solution:
Pass in userID in the JWT token. When the user clicks on the profile page, send a POST request to an endpoint that accepts the token (in a header). The backend verifies the token, extracts the userID, makes the DB call, and finally returns the response.
An advantage to this approach is that your profile route is authenticated (i.e, the route is secure).

Problem with logout user. Express server api with JWT auth

I'm trying to create a full-stack mern app. I use jwt authentication. I will save the token in local storage and the token will be removed from there with react.
I have tried with req.logout(), req.logOut() and req.session.destroy() and it doesn't work.
Thank you!
const signIn = (req, res) => {
const { email, password } = req.body;
User.findOne({ email: email })
.then((user) => {
if (!user) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
if(!user.authenticate(password)) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
const token = jwt.sign({
email: user.email,
userId: user._id.toString()
}
, 'somesupersecret'
, { expiresIn: '1h' });
res.status(200).json(
{
message: 'User successfully logged in!',
token,
userId: user._id.toString()
});
})
.catch(error => {
if (!error.statusCode) {
error.statusCode = 500;
next(error);
}
})
}
const logOut = async(req, res) => {
try{
await req.logOut();
res.status(200).json(
{
message: 'User successfully logged out!',
});
}
catch(error) {
console.log(error);
}
}
module.exports = {
signUp,
signIn,
logOut
}
I become errors like TypeError: req.logOut is not a function.
This should not be done on the server. Just remove/invalidate your jwt token that is being sent by the client. Generally the token is stored in localStorage and/or cookies. Just delete that token and refresh the page, user will logout.

stateless session api request

I am building a simple app that uses JWT for authentication. But I keeps on getting the error saying the route I GET to require a call back function.
What do I expect?
I should be getting the current user's data back.
What do I actually get?
Error: Route.get() requires a callback function but got a [object Object]
Route:
const authenticate = require("../middlewares/authenticate");
const usersController = require("../controllers").users;
app.get("/users/me", authenticate, usersController.getMe);
Model:
"use strict";
const jwt = require("jsonwebtoken");
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define(
"User",
{
email: DataTypes.STRING,
password: DataTypes.STRING
},
{
classMethods: {
associate: function(models) {
// associations can be defined here
},
findByToken: function(token) {
const User = this;
let decoded;
try {
decoded = jwt.verify(token, "leogoesger");
} catch (e) {
console.log(e);
}
return User.find({ where: { email: decoded.email } });
}
}
}
);
return User;
};
Middleware:
const { User } = require("../models/user");
const authenticate = (req, res, next) => {
console.log("called here");
const token = req.header("x-auth");
User.findByToken(token)
.then(user => {
if (!user) {
}
req.user = user;
req.token = token;
next();
})
.catch(e => {
res.status(401).send(e);
});
};
module.exports = { authenticate };
Controller:
module.exports = {
getMe(req, res) {
res.status(200).send({ message: "hello" });
}
};
Your authenticate module exports an object, yet you do this:
const authenticate = require("../middlewares/authenticate");
which means your const authenticate is an object, not your function. Change that to this:
const authenticate = require("../middlewares/authenticate").authenticate;
Or, change the module to export the function directly instead of exporting an object with the function in it.