No 'Access-Control-Allow-Origin' header is present on the requested resource (MERN) - authentication

This error is never ending, I keep getting it and it's been days I've been trying to find a solution for this annoying error.
Here is what happens when I try to log in.
My app works perfectly fine in localhost but there are alot of issue when I uploaded it to heroku and it is really annoying.
Im using
Axios.defaults.withCredentials = true;
code on my every front end.
My backend
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose")
const app = express();
const bcrypt = require("bcryptjs")
const saltRounds = 10;
const bodyParser = require("body-parser")
const cookieParser = require("cookie-parser")
const session = require("express-session")
const voterModel = require('./modules/voters.js')
const presidentModel = require('./modules/president.js')
const viceModel = require('./modules/vice.js')
const treasurerModel = require('./modules/treasurer.js')
var MongoDBStore = require('connect-mongodb-session')(session);
app.use(express.json());
const corsOptions = {
origin: 'https://incomparable-speculoos-abdd5f.netlify.app',
//update: or "origin: true," if you don't wanna add a specific one
credentials: true,
};
app.use(cors(corsOptions));
app.options('*', cors());
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }))
mongoose.connect("hidden",
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
var store = new MongoDBStore({
uri: 'hidden',
collection: 'sessions'
});
// Catch errors
store.on('error', function(error) {
console.log(error);
});
app.use(session({
secret: "hidden",
resave: false,
store: store,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24
}
}))
app.post('/login', async (req, res) => {
const email = req.body.email;
const password = req.body.password;
voterModel.find({email: email}, {"email":1}, async (err, result) => {
if (err) {
console.log(err)
} else {
if(result.length > 0) {
const user = await voterModel.findOne({email: email})
const pass = await user.comparePassword(password)
if (pass) {
req.session.user = user
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
} else {
console.log("NOT LOGGED IN")
res.send({ message: 'Invalid email or password!'})
}
}
})
})
app.post('/register', async (req, res) => {
const username = req.body.username;
const email = req.body.email;
const password = req.body.password;
// HASING PASSWORD
bcrypt.hash(password, saltRounds, async (err, hash) => {
if (err) {
console.log(err)
}
// INSERTING VALUES
const voters = await voterModel({email: email, username: username, password: hash, status: false})
// CHECKS IF EMAIL IS IN USE
const isNewEmail = await voterModel.isThisEmailInUse(email)
if (!isNewEmail) return res.send({ message: 'This email is already taken!'})
// SAVES THE INSERT DATA FOR VOTERS
await voters.save()
res.send({success: true})
})
})
app.post('/voted', async (req, res) => {
// FOR UPDATING THE VOTING STATUS
const email = req.body.email
// VARIABLES FOR CHOSEN CANDIDATES OF USER
const president = req.body.president
const vice = req.body.vice
const treasurer = req.body.treasurer
// SETS THE STATUS OF VOTER TO TRUE SO HE/SHE CAN ONLY VOTE ONCE
voterModel.updateOne({email: email}, {$set : {status: true}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
// BELOW ARE THE COMMANDS FOR INCREMENTING THE VOTE COUNT OF SELECTED CANDIDATES OF THE VOTER
presidentModel.updateOne({nickname: president}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
viceModel.updateOne({nickname: vice}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
treasurerModel.updateOne({nickname: treasurer}, {$inc : {votes: 1}}, (err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
}
})
})
app.get('/login', (req, res) => {
if (req.session.user) {
res.send({loggedIn: true, user: req.session.user})
} else {
res.send({loggedIn: false})
}
})
app.post('/checkVote', (req, res) => {
const email = req.body.email
const num = true;
voterModel.find({ $and : [{email: email}, {status : num}]},(err, result) => {
if (err) {
console.log(err)
} else {
console.log(result)
if (result.length > 0) {
res.send( {voted: true } )
} else {
res.send( {voted: false } )
}
}
})
})
app.get("/logout", (req, res) => {
req.session.destroy(err => {
if (err) return next(err)
res.status(200).send('logged out')
})
res.status(200).send('User has been logged out');
});
const PORT = process.env.PORT || 3001
app.listen(PORT, () => {
console.log('running on port 3001')
})

Related

How do I save the state of a page in Express JS?

I'm creating a website that allows users to create a video-board and display YouTube videos, and they can drag/resize these videos. I want users to be able to save their video board page in a unique URL so they can return later, and have multiple different pages.
To do this I've created a unique user id with UUID, and added this to the URL when users create a video board. Then, I connected my website to a MySQL database and used sequelize to create a table using a MVC Pattern. I want to store the state of their video board (positions, videos URL) and assign it to their url. The tables have been created, however, the issue I'm having is nothing is being sent to the database.
GitHub: https://github.com/RyanOliverV/MultiViewer
Controller index:
const controllers = {};
controllers.video = require('./video-board');
module.exports = controllers;
Controller video board:
const { models: { Video } } = require('../models');
module.exports = {
create: (req, res) => {
const { video_url, user_id, position } = req.body;
Video.create({ video_url, user_id, position })
.then(video => res.status(201).json(video))
.catch(error => res.status(400).json({ error }));
},
getAllVideos: (req, res) => {
Video.findAll()
.then(videos => res.status(200).json(videos))
.catch(error => res.status(400).json({ error }));
},
getVideoById: (req, res) => {
const { id } = req.params;
Video.findByPk(id)
.then(video => {
if (!video) {
return res.status(404).json({ error: 'Video not found' });
}
return res.status(200).json(video);
})
.catch(error => res.status(400).json({ error }));
},
update: (req, res) => {
const { id } = req.params;
const { video_url, user_id, position } = req.body;
Video.update({ video_url, user_id, position }, { where: { id } })
.then(() => res.status(200).json({ message: 'Video updated' }))
.catch(error => res.status(400).json({ error }));
},
delete: (req, res) => {
const { id } = req.params;
Video.destroy({ where: { id } })
.then(() => res.status(200).json({ message: 'Video deleted' }))
.catch(error => res.status(400).json({ error }));
},
}
Model index:
const dbConfig = require('../config/db-config');
const Sequelize = require('sequelize');
const sequelize = new Sequelize(dbConfig.DATABASE, dbConfig.USER, dbConfig.PASSWORD, {
host: dbConfig.HOST,
dialect: dbConfig.DIALECT
});
const db = {};
db.sequelize = sequelize;
db.models = {};
db.models.Video = require('./video-board') (sequelize, Sequelize.DataTypes);
module.exports = db;
Model video board:
module.exports = (sequelize, DataTypes) => {
const Video = sequelize.define('video', {
video_url: {
type: DataTypes.STRING,
allowNull: false
},
user_id: {
type: DataTypes.STRING,
allowNull: false
},
position: {
type: DataTypes.JSON,
allowNull: false
}
});
return Video;
}
Route:
const express = require('express');
const router = express.Router();
const { v4: uuidv4 } = require('uuid');
const { video } = require('../../controllers');
router.get('/', (req, res) => {
const user_id = uuidv4();
res.redirect(`/video-board/${user_id}`);
});
router.post('/', (req, res) => {
const { video_url, user_id, position } = req.body;
video.create(req, res, { video_url, user_id, position })
});
router.get('/:id', (req, res) => {
const user_id = req.params.id;
res.render('video-board', { user_id });
});
module.exports = router;
When the user clicks the 'create-video-board' button it creates a unique url, and I'm expecting this to be stored in the database with the page state of that url.

Mongoose schema validation err

i m applying mongoose to my todolist app on node js and to make sure a person doesn't add an empty new item i m using the required field in mongoose schema for new item and it gives no err untill some i checked to see if its working and try adding an empty item it gave me the err message i put into the required field but also crashed the whole app
here's the node js code
//jshint esversion:6
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose")
const app = express();
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
mongoose.connect("mongodb://localhost:27017/todolistDB")
const itemsSchema = {
name: String
// {
// type: String,
// required: [true, "naam dal na ba!$^&y"]
// }
}
const Item = mongoose.model("(Item", itemsSchema)
const welcome = new Item({ name: "welcome to list" })
const add = new Item({ name: "+ will add new item" })
const del = new Item({ name: "nuke the mofo" })
const defaultItems = [welcome, add, del]
// Item.insertMany(defaultItems, (err) => {
// if (err) { console.log("err") } else { console.log("success in default") }
// })
app.get("/", function(req, res) {
Item.find({}, (err, foundItems) => {
if (foundItems.length === 0) {
Item.insertMany(defaultItems, (err) => {
if (err) { console.log("err") } else { console.log("success in default") }
})
res.redirect("/")
} else { res.render("list", { listTitle: "today", newListItems: foundItems }); }
})
});
app.post("/", function(req, res) {
const itemName = req.body.newItem;
const newItem = new Item({ name: itemName })
newItem.save()
res.redirect("/")
// if (req.body.list === "Work") {
// workItems.push(item);
// res.redirect("/work");
// } else {
// items.push(item);
// res.redirect("/");
// }
});
app.post("/delete", function(req, res) {
const itemId = req.body.cbox
Item.findByIdAndRemove(itemId, (err) => {
if (!err) {
console.log("deleted item")
res.redirect("/")
} else { console.log("err") }
})
})
app.get("/:userList", (req, res) => {
const nameOFList = req.params.userList
})
app.get("/work", function(req, res) {
res.render("list", { listTitle: "Work List", newListItems: workItems });
});
app.get("/about", function(req, res) {
res.render("about");
});
app.listen(3000, function() {
console.log("Server started on port 3000");
});
this is the error i m getting
Server started on port 3000
C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\document.js:2980
this.$__.validationError = new ValidationError(this);
^
ValidationError: (Item validation failed: name: naam dal na ba!$^&y
at model.Document.invalidate (C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\document.js:2980:32)
at C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\document.js:2769:17
at C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\schematype.js:1333:9
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
errors: {
name: ValidatorError: naam dal na ba!$^&y
at validate (C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\schematype.js:1330:13)
at SchemaString.SchemaType.doValidate (C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\schematype.js:1314:7)
at C:\Users\zahab\Desktop\todolist-v2-starting-files\node_modules\mongoose\lib\document.js:2761:18
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
properties: {
validator: [Function (anonymous)],
message: 'naam dal na ba!$^&y',
type: 'required',
path: 'name',
value: ''
},
kind: 'required',
path: 'name',
value: '',
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
},
_message: '(Item validation failed'
}
[nodemon] app crashed - waiting for file changes before starting...

NextAuth authentication not working on Deployment on Vercel (Working on localhost)

Used credentials for authentication with nextauth. My code is not working on vercel deployment but working on localhost.
I used the basic cresdentials for authentication username and password but not able to get the session object after signing up from SignUpPage from the pages folder
[...nextauth].js
export default NextAuth({
session: {
jwt: true,
},
providers: [
Credentials({
async authorize(credentials) {
const client = await MongoClient.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const usersCollection = client.db().collection("users");
const user = await usersCollection.findOne({
username: credentials.username,
});
if (!user) {
client.close();
throw new Error("No user found!");
}
const isValid = await compare(credentials.password, user.password);
if (!isValid) {
client.close();
throw new Error("Could not log you in!");
}
client.close();
return { username: user.username };
},
}),
],
callbacks: {
jwt: async ({ token, user }) => {
if (user) {
token.user = user;
}
return token;
},
session: async ({ session, token }) => {
if (token) {
session.user = token.user;
}
return session;
},
},
secret: process.env.SECRET,
jwt: {
secret: process.env.SECRET,
encryption: true,
},
});
pages/api/auth/signup.js
async function handler(req, res) {
if (req.method !== "POST") {
return;
}
const data = req.body;
const { username, password } = data;
if (!username || !password || password.trim().length < 7) {
res.status(422).json({
message:
"Invalid input - password should also be at least 7 characters long.",
});
return;
}
const client = await MongoClient.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
const db = client.db();
const existingUser = await db
.collection("users")
.findOne({ username: username });
if (existingUser) {
res.status(422).json({ message: "User exists already!" });
client.close();
return;
}
const hashedPassword = await hash(password, 12);
const result = await db.collection("users").insertOne({
username: username,
password: hashedPassword,
});
res.status(201).json({ message: "Created user!" });
client.close();
}
export default handler;
pages/SignUpPage.js
useEffect(() => {
getSession().then((session) => {
if (session) {
router.push("/");
} else {
setIsLoading(false);
}
});
}, [router]);
if (isLoading) {
return <p>Loading...</p>;
}
const createUser = async (username, password) => {
const response = await fetch("/api/auth/signup", {
method: "POST",
body: JSON.stringify({ username, password }),
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.message || "Something went wrong!");
}
return data;
};
const submitHandle = async (username, password) => {
if (login) {
const result = await signIn("credentials", {
redirect: false,
username: username,
password: password,
});
if (!result.error) {
router.push("/");
}
} else {
try {
const result = await createUser(username, password);
console.log("result", result);
router.push("/");
} catch (error) {
console.log(error);
}
}
};
Looks like you have used environment variables. Make sure you have updated them with relevant values.
for example,
NEXTAUTH_URL=http://localhost:3000
to
NEXTAUTH_URL=https://youdomain.com

How to properly logout with JWT using Passport Strategies?

I am new to JWT and Passport so I started following a MERN tutorial on Youtube by NoobCoder that deals with authentication and authorization using JWT. I reached the part where the route deals with '/logout' and I get Unauthorized as a reply from Postman. The code so far is exactly the same by the looks of it. Can someone help me understand what is wrong here?
I have attached the code in the bottom. Please let me know if more information is required.
Here is the code:
app.js
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
const mongoose = require('mongoose');
app.use(cookieParser());
app.use(express.json());
mongoose.connect('mongodb://localhost:27017/mernauth', {useNewUrlParser: true, useUnifiedTopology: true}, () => {
console.log('Successfully connected to DB');
});
const userRouter = require('./routes/User');
app.use('/user', userRouter);
app.listen(5000, () => {
console.log('express server started');
});
passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const JwtStrategy = require('passport-jwt').Strategy;
const User = require('./models/User');
const cookieExtractor = req => {
let token = null;
if(req && req.cookies) {
token = req.cookies['access_token'];
}
return token;
}
// Authorization
passport.use(new JwtStrategy({
jwtFromRequest: cookieExtractor,
secretOrKey: 'NoobCoder'
}, (payload, done) => {
User.findById({_id: payload.sub}, (err, user) => {
if(err) {
return done(err, false);
}
if(user) {
return done(null, user);
}
else {
return done(null, false);
}
})
}));
// Authenticated local strategy using username and password
passport.use(new LocalStrategy((username, password, done) => {
User.findOne({username}, (err, user) => {
// Something went wrong with DB
if(err) {
return done(err);
}
// If no user exists; null = no error; false = user does not exist
if(!user) {
return done(null, false);
}
// Check if password is correct; callback cb = done
user.comparePassword(password, done);
});
}));
User.js (route)
const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Todo = require('../models/Todo');
const signToken = userID => {
return JWT.sign({
iss: "NoobCoder",
sub: userID
}, "NoobCoder", {expiresIn: "1h"});
}
userRouter.post('/register', (req, res) => {
const {username, password, role} = req.body;
User.findOne({username}, (err, user) => {
if(err) {
res.status(500).json({message: {msgBody: "Error has occured", msgError: true}})
}
if(user) {
res.status(400).json({message: {msgBody: "Username is already taken", msgError: true}})
}
else {
const newUser = new User({username, password, role});
newUser.save(err => {
if(err) {
res.status(500).json({message: {msgBody: "Error has occured", msgError: true}})
}
else {
res.status(201).json({message: {msgBody: "Account Successfully Created", msgError: false}})
}
})
}
})
});
userRouter.post('/login', passport.authenticate('local', {session: false}), (req, res) => {
if(req.isAuthenticated()) {
const {_id, username, role} = req.user;
const token = signToken(_id);
res.cookie('access_token', token, {httpOnly: true, sameSite: true});
res.status(200).json({isAuthenticated: true, user: {username, role}})
}
});
userRouter.get('/logout', passport.authenticate('jwt', {session: false}), (req, res) => {
res.clearCookie('access_token');
res.json({user: {username: '', role: ''}, success: true});
});
module.exports = userRouter;
User.js (model)
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
min: 6,
max: 15
},
password: {
type: String,
required: true,
},
role: {
type: String,
enum: ['user', 'admin'],
required: true
},
todos: [{type: mongoose.Schema.Types.ObjectId, ref: 'Todo'}]
});
UserSchema.pre('save', function(next) {
if(!this.isModified('password')) {
return next()
}
bcrypt.hash(this.password, 10, (err, passwordHash) => {
if(err) {
return next(err);
}
this.password = passwordHash;
next();
});
});
UserSchema.methods.comparePassword = function(password, cb) {
bcrypt.compare(password, this.password, (err, isMatch) => {
if(err) {
return cb(err);
}
else {
if(!isMatch) {
return cb(null, isMatch)
}
return cb(null, this);
}
})
};
module.exports = mongoose.model('User', UserSchema);
Perhaps the /logout route is unauthorised because the JWT token is not present?
JWT token presence can be verified by ensuring that the cookieExtractor function is returning a token
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
Source

nuxtjs - global shared editable server variables

I'm using nuxtjs and I use app authentication against a restful API. I want to store in a server side variable my token, wich I use everywhere to request informations to the API, but I cannot store it in process.env variabls because I need to modify it when it expires (after 1 hour). The token is for the app, not for users, so every call to the api have to use the same token. I try to use fs to save my token in a json file and refresh it when it expires, but I cannot use fs in nuxtjs, it tells me that fs doesn't exists, maybe because I try to use it in client side.
Do you know how can I do that?
Thank you
I solved by using express in server side envirenment, I had to put server middleware configuration in nuxt.config.js:
const bodyParser = require('body-parser')
const session = require('express-session')
module.exports = {
...
serverMiddleware: [
bodyParser.json(),
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 3600000 }
}),
'~/server'
],
...
and on /server/index.js file :
const express = require('express')
const api = require('./api')
// Create express router
const router = express.Router()
// Transform req & res to have the same API as express
// So we can use res.status() & res.json()
var app = express()
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
router.get('/myroute', (req, res) => {
api.get('myroute')
.then((data) => {
res.json({success: true})
})
.catch((e) => {
res.status(500).json({ message: 'An error occurred' })
})
})
module.exports = {
path: '/server',
handler: router
}
and on my /server/api.js file
const parameters = require('./parameters.js')
const router = require('./router.js')
const axios = require('axios')
const auth = {
accessToken: null,
expiresAt: null
}
const getToken = () => {
const expiresAt = auth.expiresAt
const accessToken = auth.accessToken
const expires = expiresAt ? (new Date()).getTime() : null
if (expires && expires - expiresAt > 0) {
return new Promise((resolve, reject) => {
resolve(accessToken)
})
}
return new Promise((resolve, reject) => {
axios.get(parameters.api + router.token, {
params: parameters.auth
})
.then(({data}) => {
auth.accessToken = data.access_token
auth.expiresAt = (new Date()).getTime() + data.expires_in - 60
resolve(data.access_token)
})
.catch((e) => {
reject(e)
})
})
}
const getCompleteRoute = (route) => {
return new Promise((resolve, reject) => {
getToken()
.then((token) => {
resolve(parameters.api + router[route] + '?access_token=' + token)
})
.catch((e) => {
reject(e)
})
})
}
const get = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.get(completeRoute, {params: params})
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
const post = (route, params) => {
return new Promise((resolve, reject) => {
getCompleteRoute(route)
.then((completeRoute) => {
axios.post(completeRoute, params)
.then(({data}) => {
resolve(data)
})
.catch((e) => {
reject(e)
})
})
.catch((e) => {
reject(e)
})
})
}
module.exports = {
get: get,
post: post
}