I am trying to implement signup, signin, getcurrentuser, getallusers functionalities.
except getllusers everything is working fine.
I have used JWT Token verification
help me out to find, how to query all users if a user is logged in
Resolvers
const { ApolloError, AuthenticationError } = require("apollo-server-express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const { generateToken } = require("../utils/index");
module.exports = {
Query: {
me(parent, args, { models, authUser }) {
return models.User.findByPk(authUser.id);
},
getAllUsers: async (parent, args, { models }) => {
const allUsers = await models.User.findAll();
console.log(allUsers);
return allUsers;
},
users: async (parent, args, { models }) => {
await models.User.findAll();
},
},
Mutation: {
async signUp(parent, { username, email, password }, { models }) {
const userExists = await models.User.findOne({ where: { email } });
if (userExists) {
throw new ApolloError("Email is already in use");
}
const user = await models.User.create({ username, email, password });
// ?console.log(token);
return { token: generateToken(user) };
},
async signIn(parent, { email, password }, context) {
const user = await context.models.User.findOne({ where: { email } });
if (!user) {
throw new AuthenticationError("Invalid Email");
}
const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
throw new AuthenticationError("Invalid Password");
}
return { token: generateToken(user) };
},
// async signIn(parent, { email, password }, { models }) {
// const user = await models.User.findOne({ where: { email } });
// if (!user) {
// throw new AuthenticationError("Invalid Email");
// }
// const isPasswordValid = await bcrypt.compare(password, user.password);
// if (!isPasswordValid) {
// throw new AuthenticationError("Invalid Password");
// }
// return { token: generateToken(user) };
// },
},
};
Type Defs
const { gql } = require("apollo-server-express");
module.exports = gql`
type User {
id: ID!
username: String!
email: String!
role: Role!
avatar: String
createdAt: DateTime!
updatedAt: DateTime!
}
enum Role {
ADMIN
USER
}
type Token {
token: String!
}
extend type Mutation {
signUp(username: String!, email: String!, password: String!): Token!
signIn(email: String!, password: String!): Token!
}
extend type Query {
getAllUsers: User
users: User
me: User!
}
`;
Here is my Index.JS file
My Headers
const express = require("express");
const { ApolloServer, gql } = require("apollo-server-express");
const models = require("./models");
const typeDefs = require("./typedefs");
const resolvers = require("./resolvers");
const { getAuthUser } = require("./utils");
const app = express();
const port = 5000;
Server Initializaation
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const authUser = getAuthUser(req);
console.log("Auth User", authUser);
return { models, authUser };
},
});
server.applyMiddleware({ app, cors: true })
app.listen(port, () => console.log(`started at ${port} ${server.graphqlPath}`));
Related
Hey I am testing on postman as an admin to add category on my project, I have successfully created admin user and login, but when I tried to add category, postman say: TypeError: Cannot read properties of undefined (reading 'role') can anyone help?
Here is my user model:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: ["user", "admin"],
default: "user",
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
here is my auth middleware:
const jwt = require("jsonwebtoken");
const User = require("../models/user");
const { signupUser, loginUser } = require("../controller/adminauth");
exports.auth = (req, res, next) => {
try {
if (req.header.authorization) {
const token = req.header.authorization.split("")[1];
const isCustomAuth = token.length < 500;
let decodeData;
if (token && isCustomAuth) {
decodeData = jwt.verify(token, process.env.JWT_SECRET);
req.UserId = decodeData?.id;
} else {
decodeData = jwt.decode(token);
req.UserId = decodeData?.sub;
}
}
} catch (error) {
console.log(error);
// res.status(400).json({ message: "Authorization required" });
} next ()
};
exports.adminMiddleware = (req, res, next) => {
if (!req.userId.role === "admin") {
return res.status(400).json({ message: "Access denied" });
}
next();
};
Here is my admin auth controller:
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
exports.loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser) {
return res.status(400).json({ message: "User does not exists." });
}
if (!existingUser.role === "admin") {
return res.status(400).json({ message: "User is not admin." });
}
const isPasswordCorrect = await bcrypt.compare(
password,
existingUser.password
);
if (!isPasswordCorrect)
return res.status(400).json({ message: "Invalid credentials." });
const token = jwt.sign(
{
email: existingUser.email,
id: existingUser._id,
role: existingUser.role,
},
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result: existingUser, token });
} catch (error) {
console.log(error);
}
};
exports.signupUser = async (req, res) => {
const { firstName, lastName, email, password, confirmPassword } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: "Admin already exists." });
if (!password == confirmPassword)
return res.status(400).json({ message: "Password don't match" });
const hashedPassword = await bcrypt.hash(password, 12);
const result = await User.create({
email,
password: hashedPassword,
firstName,
lastName,
role: "admin",
});
const token = jwt.sign(
{ email: result.email, id: result._id, role: result.role },
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result, token });
} catch (error) {
console.log(error);
}
};
Here is my category route:
const express = require("express");
const { addCategory, getCategories } = require("../controller/category");
const { auth, adminMiddleware } = require("../middleware/auth");
const router = express.Router();
router.post("/category/create", auth, adminMiddleware, addCategory);
router.get("/category/getcategory", getCategories);
module.exports = router;
In your auth middleware,
change your exports.auth with the following code:
exports.auth = (req, res, next) => {
try {
if (req.header.authorization) {
const token = req.header.authorization.split("")[1];
const isCustomAuth = token.length < 500;
let decodeData;
if (token && isCustomAuth) {
decodeData = jwt.verify(token, process.env.JWT_SECRET);
req.UserId = decodeData||{}; //change this line
} else {
decodeData = jwt.decode(token);
req.UserId = decodeData?.sub;
}
}
} catch (error) {
console.log(error);
res.status(400).json({ message: "Authorization required" });
} next ()
};
I am building a user signup and login api and admin signup and login using express and currently I am testing in the postman, but somehow postman keeps return "error": "firstName is not defined" even though I posted firstname etc. here is my code, can anyone help me to explain it what is wrong? I saw so many videos using all different kinds of method, like generateAuthtakoken in the user.model or joi password library, it is just so overwhelming, can you help me to point to a direction as to how to use express to create ?
this is my user.model file:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const validator = require("validator");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: ["user", "admin"],
default: "user",
},
contactNumber: { type: String },
profilePicture: { type: String },
},
{ timestamps: true }
);
//static signup method
userSchema.statics.signup = async function (email, password) {
//validation
if (!firstName || !lastName || !email || !password) {
throw Error("All fields must be filled");
}
if (!validator.isEmail(email)) {
throw Error("Email is not valid");
}
if (!validator.isStrongPassword(password)) {
throw Error("Password is not strong enough");
}
const exists = await this.findOne({ email });
if (exists) {
throw Error("Email already in use");
}
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
const user = await this.create({ email, password: bcrypt.hash });
return user;
};
//static login method
userSchema.statics.login = async function (email, password) {
if (!firstName || !lastName || !email || !password) {
throw Error("All fields must be filled");
}
const user = await this.findOne({ email });
if (!user) {
throw Error("Incorrect Email");
}
const match = await bcrypt.compare(password, user.password);
if (!match) {
throw Error("Incorrect password");
}
return user;
};
module.exports = mongoose.model("User", userSchema);
this is my controller file:
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const createToken = (_id) => {
jwt.sign({ _id }, process.env.JWT_SECRET, { expiresIn: "3d" });
};
//login user
const loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.login(email, password);
// create token
const token = createToken(user._id);
res.status(200).json({ email, token });
} catch (error) {
res.status(400).json({ error: error.message });
}
res.json({ msg: "login user" });
};
//signup user
const signupUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.signup(email, password);
// create token
const token = createToken(user._id);
res.status(200).json({ email, token });
} catch (error) {
res.status(400).json({ error: error.message });
}
res.json({ msg: "login user" });
};
module.exports = { signupUser, loginUser };
and my router file:
const express = require("express");
const router = express.Router();
const { signupUser, loginUser } = require("../controller/auth");
//login route
router.post("/login", loginUser);
//signup route
router.post("/signup", signupUser);
module.exports = router;
where exactly do you get this error. Please provide full details to regenerate this error.
But as i could guess
In your static login method you do not need firstName and LastName.
In your signup user method you should be passing those missing required db fields as in your model.
I am trying to wrote RESTFull api with express and mongodb . sections for registraion and login are work properly but when I trying to updatOneById it dosent work .and send you can update only uor accout i delete if cluse but it still same and doesnt work .
index.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const userRoute = require("./routes/users");
const authRoute = require("./routes/auth");
dotenv.config();
mongoose.connect(
process.env.ACCESS_KEY,
{ useNewUrlParser: true, useUnifiedTopology: true },
() => {
console.log("Connected to MongoDB");
}
);
//middleware
app.use(express.json());
app.use(helmet());
app.use(morgan("common"));
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.listen(8800, () => {
console.log("Backend server is running!");
});
and these are my routers
first is Auth.js
const router = require("express").Router();
const User = require("../models/User");
const bcrypt = require("bcrypt");
//REGISTER
router.post("/register", async (req, res) => {
try {
//generate new password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
//create new user
const newUser = new User({
username: req.body.username,
email: req.body.email,
password: hashedPassword,
});
//save user and respond
const user = await newUser.save();
res.status(200).json(user);
} catch (err) {
res.status(500).json(err)
}
});
//LOGIN
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({ email: req.body.email });
!user && res.status(404).json("user not found");
const validPassword = await bcrypt.compare(req.body.password, user.password)
!validPassword && res.status(400).json("wrong password")
res.status(200).json(user)
} catch (err) {
res.status(500).json(err)
}
});
module.exports = router;
seconde is user router
const User = require("../models/User");
const router = require("express").Router();
const bcrypt = require("bcrypt");
//update user
router.put("/:id", async (req, res) => {
if (req.body.userId === req.params.id || req.body.isAdmin) {
if (req.body.password) {
try {
const salt = await bcrypt.genSalt(10);
req.body.password = await bcrypt.hash(req.body.password, salt);
} catch (err) {
return res.status(500).json(err);
}
}
try {
const user = await User.findByIdAndUpdate(req.params.id, {
$set: req.body,
});
res.status(200).json("Account has been updated");
} catch (err) {
return res.status(500).json(err);
}
} else {
return res.status(403).json("You can update only your account!");
}
});
//delete user
router.delete("/:id", async (req, res) => {
if (req.body.userId === req.params.id || req.body.isAdmin) {
try {
await User.findByIdAndDelete(req.params.id);
res.status(200).json("Account has been deleted");
} catch (err) {
return res.status(500).json(err);
}
} else {
return res.status(403).json("You can delete only your account!");
}
});
//get a user
router.get("/:id", async (req, res) => {
try {
const user = await User.findById(req.params.id);
const { password, updatedAt, ...other } = user._doc;
res.status(200).json(other);
} catch (err) {
res.status(500).json(err);
}
});
//follow a user
router.put("/:id/follow", async (req, res) => {
if (req.body.userId !== req.params.id) {
try {
const user = await User.findById(req.params.id);
const currentUser = await User.findById(req.body.userId);
if (!user.followers.includes(req.body.userId)) {
await user.updateOne({ $push: { followers: req.body.userId } });
await currentUser.updateOne({ $push: { followings: req.params.id } });
res.status(200).json("user has been followed");
} else {
res.status(403).json("you allready follow this user");
}
} catch (err) {
res.status(500).json(err);
}
} else {
res.status(403).json("you cant follow yourself");
}
});
//unfollow a user
router.put("/:id/unfollow", async (req, res) => {
if (req.body.userId !== req.params.id) {
try {
const user = await User.findById(req.params.id);
const currentUser = await User.findById(req.body.userId);
if (user.followers.includes(req.body.userId)) {
await user.updateOne({ $pull: { followers: req.body.userId } });
await currentUser.updateOne({ $pull: { followings: req.params.id } });
res.status(200).json("user has been unfollowed");
} else {
res.status(403).json("you dont follow this user");
}
} catch (err) {
res.status(500).json(err);
}
} else {
res.status(403).json("you cant unfollow yourself");
}
});
module.exports = router;
**and this is my schema model **
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
require: true,
min: 3,
max: 20,
unique: true,
},
email: {
type: String,
required: true,
max: 50,
unique: true,
},
password: {
type: String,
required: true,
min: 6,
},
profilePicture: {
type: String,
default: "",
},
coverPicture: {
type: String,
default: "",
},
followers: {
type: Array,
default: [],
},
followings: {
type: Array,
default: [],
},
isAdmin: {
type: Boolean,
default: false,
},
desc: {
type: String,
max: 50,
},
city: {
type: String,
max: 50,
},
from: {
type: String,
max: 50,
},
relationship: {
type: Number,
enum: [1, 2, 3],
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
finally I find that .all of my code is ok but the problem is my cluster on mongodb.
you have to delete your cluster and run it again the problem will be solved .
I have created 2 table Token and users and i want to associate it. After associating i want to set the token value to my user and associate my userId with the token table. for this i have used setUser & addToken but my setUser is throwing error while addToken is working fine.
const { nanoid } = require('nanoid/async')
const argon2 = require('argon2')
const jwt = require('../lib/jwt')
module.exports = (sequelize, Sequelize, Token, Task) => {
const User = sequelize.define("users", {
age: {
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
}, {
defaultScope: {
attributes: { exclude: ['password'] },
},
scopes: {
withPassword: {
attributes: {}
}
}
});
User.beforeCreate(async (user, options) => {
const hashedPassword = await argon2.hash(user.password)
user.password = hashedPassword
})
User.prototype.generateToken = async function generateToken() {
const jwtid = await nanoid()
const token = jwt.sign({ sub: this.id }, { jwtid })
const userToken = await Token.create({ jti: jwtid })
await this.setUser(token)
await this.addToken(userToken)
return token
}
User.prototype.verifyPassword = async function verifyPassword(password) {
console.log('verify Password instance method', { password, hash: this.password })
return argon2.verify(this.password, password)
}
User.hasMany(Token)
Token.belongsTo(User)
User.hasMany(Task)
Task.belongsTo(User)
return User;
};
Please help me fix this so that my token table associate with user table
App.js File
const express = require('express');
const bodyParser = require('body-parser');
const graphqlHttp = require('express-graphql');
const { buildSchema } = require('graphql');
const isAuth = require('./middleware/is-auth');
var mysql = require('mysql');
const app = express();
const jwt = require('jsonwebtoken');
var connection = mysql.createConnection({
host : 'localhost', //mysql database host name
user : 'root', //mysql database user name
password : '', //mysql database password
database : 'test' //mysql database name
});
connection.connect(function(err) {
if (err) throw err
console.log('You are now connected with mysql database...')
})
app.use(bodyParser.json());
app.use(isAuth);
app.use(
'/graphql',
graphqlHttp({
schema: buildSchema(`
type users {
id: String!
username: String!
password: String!
role: String!
name: String!
photo: String!
}
type AuthData
{
userID: String!
token: String!
tokenExpiration: Int!
}
type RootQuery {
getUsers: [users!]!
login(username: String!, password: String!): AuthData!
}
type RootMutation {
createUsers(name: String): String
}
schema {
query: RootQuery
mutation: RootMutation
}
`),
rootValue: {
login: async ({username,password}) => {
return new Promise((resolve, reject) => {
connection.query('select * from users where username = "'+username+'"', (error, results, fields) => {
if (error) {
reject(error)
} else {
resolve(results);
}
})
}).then(function(result) {
const users = result;
if(!users || users[0] == null)
{
throw new Error('User does not exist')
}
const token = jwt.sign({userID: users[0]['id'], username: users[0]['username']}, 'SomeSuperSecretKey', {
expiresIn: '1h'
});
return { userID: users[0]['id'], token, token,tokenExpiration: 1}
})
},
getUsers: async (req) => {
if(!req.isAuth)
{
throw new Error('Unauthenticated');
}
// Note, we have to return the Promise here
return new Promise((resolve, reject) => {
connection.query('select * from users', (error, results, fields) => {
if (error) {
reject(error)
} else {
// Don't stringify
resolve(results)
}
})
})
},
},
graphiql: true
})
);
app.listen(3000);
is-auth.js File
const jwt = require ('jsonwebtoken');
module.exports = (req, res, next) => {
const authHeader = req.get('Authorization');
if(!authHeader){
console.log("Here");
req.isAuth = false;
return next();
}
const token = authHeader.split(' ')[1]; // bearer tokenValue
if(!token || token === ''){
console.log("Here1");
req.authHeader = false;
return next();
}
let decodedToken;
try
{
console.log(token);
decodedToken = jwt.verify(token, 'SomeSuperSecretKey'); //same key used in app.js
}catch(err){
console.log(err);
req.isAuth = false;
return next();
}
if(!decodedToken){
req.isAuth = true;
req.userID = decodedToken.userID;
return next();
}
}
Post man Api
The jwt.verify function doesnt return any thing it got stuck and api results no response. So the problem is in the verify function it got stuck in it. And if I enter a own custom token it gives another error, which tells you are not allowed to enter your own custom token onlt jwt generated tokens can be used.