I'm getting a cors error when trying to login into my MERN app
Screenshot.It's working fine locally and in the Network tab it shows a 503 error code.
My Heroku logs show these messages.
const err = new MongooseError(message);
MongooseError: Operation users.findOne() buffering timed out after 10000ms
But, I'm getting the 'User Name verified' console log in the Heroku logs which is present in the validation.js file below. So the backend connection is fine I think.
I used 0.0.0.0/0 in MongoDB network access and used cors package for all origin.
Also tried using mongoose.connect using async/await, and using the older drivers in MongoDB but nothing seems to work. If anyone knows how to fix it please respond.
Here is my code in node.js.
index.js
const express = require('express')
const cors = require('cors')
const DBConnect = require('./mongo')
const Login = require('./routes/login')
const Google = require('./routes/google')
const Register = require('./routes/register')
const SaveData = require('./routes/saveData')
require('dotenv').config()
const port = process.env.PORT || 5000
const app = express()
const corsOptions = {
origin: '*',
credentials: true,
optionSuccessStatus: 200
}
app.use(cors(corsOptions))
app.use(express.json())
DBConnect().then(()=>console.log('DB Connection successfull!'))
app.get('/', (req,res)=>{ res.json('Server running')})
app.use('/api/gauth', Google)
app.use('/api/login', Login)
app.use('/api/register', Register)
app.use('/api/save', SaveData)
app.listen(port,()=>console.log(`Server listening on port ${port}`))
mongo.js
const mongoose = require('mongoose')
module.exports = async () => {
const username = process.env.USER_NAME
const password = process.env.PASSWORD
const cluster = process.env.CLUSTER
const dbname = process.env.DB_NAME
const url = `mongodb+srv://${username}:${password}#${cluster}.mongodb.net/${dbname}?retryWrites=true&w=majority`
const mongooseOptions = {
useNewUrlParser: true,
useUnifiedTopology: true
}
await mongoose.connect(url, mongooseOptions)
.then(x => console.log(`Connected to MongoDB : ${x.connections[0].name}`))
.catch(err => console.error('Error connecting to mongo', err))
}
google.js
const app = require('express')()
const googleAuth = require('../components/validation')
const userModel = require('../components/models')
const bcrypt = require('bcrypt')
const JWT = require('jsonwebtoken')
const dotenv = require('dotenv')
dotenv.config()
app.post('/', async (req,res)=>{
const user = await googleAuth(req.body.token)
const emailExist = await userModel.findOne({ email: user.email })
const token = JWT.sign({_id: user.id}, process.env.TOKEN_KEY)
const data = {
token: token,
email: user.email,
name: user.name,
image: user.image,
data: emailExist && emailExist.data || []
}
if(!emailExist){
const salt = await bcrypt.genSalt(10)
const cipherPass = await bcrypt.hash(user.id, salt)
const newUser = new userModel({
username: user.name,
email: user.email,
password: cipherPass,
image: user.image,
data: []
})
try{
await newUser.save()
res.status(200).json(data)
}catch (err){
res.status(500).json(err)
}
}else{
res.status(200).json(data)
}
})
module.exports = app
validation.js
const { OAuth2Client } = require('google-auth-library')
const client = new OAuth2Client(process.env.OAUTH_ID)
const googleAuth = async token => {
const ticket = await client.verifyIdToken({
idToken: token,
audience: process.env.OAUTH_ID
})
const payload = ticket.getPayload()
// console.log('Paylod:', payload)
console.log(`User ${payload.name} verified`)
const { sub, name, email, picture } = payload
const userId = sub
return { id:userId, name:name, email:email, image:picture}
}
module.export = googleAuth
Related
I am working on a backend for a Online mediconsult app and I came across this error in the JWT authentication. Since I am a newbie I dunno much about this topic. I have this 3 routes on my NodeJS /register, /login, /appointments. I was able to hit "/register" and "/login" perfectly fine. But when I copy the JWT token generated by "/login" route and paste it 'authorization' header it throws the problem.
node:internal/errors:484
ErrorCaptureStackTrace(err);
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:393:5)
at ServerResponse.setHeader (node:_http_outgoing:644:11)
at ServerResponse.header (C:\Users\krish\Desktop\mrcooper-task\server\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (C:\Users\krish\Desktop\mrcooper-task\server\node_modules\express\lib\response.js:174:12)
at module.exports.login (C:\Users\krish\Desktop\mrcooper-task\server\controllers\authController.js:62:7) {
code: 'ERR_HTTP_HEADERS_SENT'
}
Node.js v18.12.0
A strange thing is, when I restart the server again with the same auth token, it works!.
Wonder why would it hit the above error before restarting ?
Code
index.js
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const app = express();
require('dotenv').config();
//External routes
const authRoutes = require("./routes/authRoutes");
const appointRoutes = require("./routes/appointRoutes");
// Middlewares
app.use(cors());
app.use(express.json());
//DB connection
const dbURI =
process.env.DB_URL;
mongoose
.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then((result) =>
app.listen(8080, () =>
console.log("App sucessfully started on localhost port 8080")
)
)
.catch((err) => console.log(err));
//Internal routes
app.use(authRoutes);
app.use(appointRoutes);
appointRoutes.js
const { Router } = require("express");
const verify = require("./verifyToken")
const router = Router();
router.get("/appointments",verify, (req, res) => {
res.send({ message: "Appointment route" });
});
module.exports = router;
authRoutes.js
const { Router } = require("express");
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { registerValidator, loginValidator } = require("../validation");
const router = Router();
router.post("/register", async (req, res) => {
//Validate data before creating a user
const { error } = registerValidator(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
//Check if email already exists
const emailExists = await User.findOne({ email: req.body.email });
if (emailExists) {
return res.status(400).send("Email already exists");
}
const { name, email, password, catogery, DOB } = req.body;
//Hash password
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
//console.log(hashedPassword);
try {
const user = await User.create({
name,
email,
password: hashedPassword,
catogery,
DOB,
});
res.status(201).json({ user: user._id });
} catch (err) {
//console.log(err);
res.status(400).send(err);
}
});
router.post("/login", async (req, res) => {
const { email, password } = req.body;
//Validate data before authenticating a user
const { error } = loginValidator(req.body);
if (error) {
return res.status(400).send(error.details[0].message);
}
//Check if email dosen't exists
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(400)
.send("Email dosen't exists. Please register and try again");
}
//Passowrd is incorrect
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) return res.status(400).send("Invalid Passowrd");
//Create and assign JWT token
const token = jwt.sign({_id: user._id}, process.env.TOKEN_SECRET)
res.header('auth-token', token).send(token);
//console.log(email, password);
res.send("Logged In!");
});
module.exports = router;
Here's what I did
I did few googles and searches on this error and found out that this error mainly throws out when we return multiple response per cycle. I checked the code below and I did'nt see multiple response coming from neither /login route nor /appointments route. Would there be any response leaks from if conditions accidentaly?
When I exit from nodemon and start again with the same take generated, now it can hit the /appointment. I wonder how it works ?
You get error when function like this
if(statement){
res.send(something)
}
res.send(something)
because code is continue after res.send() function
You must fix it to
if(statement){
return res.send(something)
}
return res.send(something)
and your res.send function in authController.js:62:7
I am simply trying to create a hashedpassword using bcryptjs and console.log that password so that I can copy and use it
i am using postman to test my POST request my plan is to send the request body as(email, password) using postman and i will read the body and pass the password to bcryptjs which will generate a hashedpassword and i want to console.log that out
now hashedpassword is not generated and also postman is not responding please help
index.js:
require('dotenv').config()
const exppess=require('express')
const cookieParser=require('cookie-parser')
const cors=require('cors')
const { verify }=require('jsonwebtoken')
const { hash, compare } = require('bcryptjs');
const bcrypt = require("bcrypt");
const { DB } = require('./DB');
const server=exppess()
server.use(cookieParser )
server.use(exppess.json )
server.use(exppess.urlencoded({ extended: true }))
server.post("/register",async (req,res)=>{
const { email, password } = req.body
try{
const hashedPassword = await hash(password, 10)
console.log(hashedPassword)
}
catch(err){
res.send({
error: `${err.message}`,
})
}
})
server.listen(process.env.PORT, () => {
console.log('server started on port: '+process.env.PORT);
});
.env file
ACCESS_TOKEN_SECRET=weibenrules
REFRESH_TOKEN_SECRET=weibenrulesevenmore
PORT=4000
Terminal:screenshot
Postman:
in the body i am setting email and password as key value pair
require('dotenv').config()
const exppess=require('express')
const cookieParser=require('cookie-parser')
const cors=require('cors')
const { verify }=require('jsonwebtoken')
const { hash, compare } = require('bcryptjs');
const bcrypt = require("bcrypt");
const { DB } = require('./DB');
const server=exppess()
server.use(cookieParser )
server.use(exppess.json )
server.use(exppess.urlencoded({ extended: true }))
server.post("/register",async (req,res)=>{
const { email, password } = req.body
try{
const hashedPassword = await hash(password, 10)
console.log(hashedPassword)
res.send(hashedPassword)
}
catch(err){
res.send({
error: `${err.message}`,
})
}
})
server.listen(process.env.PORT, () => {
console.log('server started on port: '+process.env.PORT);
});
I have been following the www.howtographql.com tutorials but i am stuck as i am not able to add authorization token in http headers. As soon as i write the authorization token it gives an error - 'Server cannot be reached'
index.js
const { ApolloServer } = require('apollo-server');
const { PrismaClient } = require('#prisma/client');
const fs = require('fs');
const path = require('path');
const { getUserId } = require('./utils');
const Query = require('./resolvers/Query');
const Mutation = require('./resolvers/Mutation');
const User = require('./resolvers/User');
const Link = require('./resolvers/Link');
const prisma = new PrismaClient();
const resolvers = {
Query,
Mutation,
User,
Link
}
const server = new ApolloServer({
typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf-8'
),
resolvers,
context:({ req }) => {
return {
...req,
prisma,
userId: req && req.headers.authorization ? getUserId(req) : null
};
}
});
server.listen()
.then(({ url }) => console.log(`Server is running on ${url}`)
);
so I get this error every time I re-render the site
" GET http://localhost:3000/api/ShopItems 431 (Request Header Fields Too Large)"
I can see that my fetch doesn't go as planed and invokes the error above ⬆️
The chrome developer tool points me to the "ShopItemsActions" fill
import { FETCH_SHOPITEMS } from "../types"
export const fetchShopItems = () => async (dispatch) => {
const res = await fetch("/api/ShopItems");
const data = res.json();
console.log(data);
dispatch({
type: FETCH_SHOPITEMS,
payload: data
});
}
The chrome developer tool mark the third line "const res = await fetch("/api/ShopItems")"
Question: how can i fix this error?
Edit:
the server side code
const express = require("express");
const bodyParser = require("body-parser");
const mongoose = require("mongoose");
const shortid = require('shortid');
const app = express();
app.use(bodyParser.json());
mongoose.connect("mongodb://localhost/bread_project_db", {
useNewUrlParser:true,
useCreateIndex: true,
useUnifiedTopology:true,
});
const ShopItem = mongoose.model(
"ShopItems",
new mongoose.Schema({
id: { type: String, default: shortid.generate },
name: String,
image: String,
price: Number,
info: String,
flourType: [String],
}))
app.get("/api/ShopItems", async (req, res)=>{
const ShopItems = await ShopItem.find({});
res.send(ShopItems);
});
app.post("/api/ShopItems", async (req, res)=>{
const newShopItem = new ShopItem(req.body);
const savedShopItem = await newShopItem.save();
res.send(savedShopItem);
});
app.delete("/api/ShopItems/:id", async (req, res) => {
const deletedShopItem = await ShopItem.findByIdAndDelete(req.params.id);
res.send(deletedShopItem);
});
const port = process.env.PORT || 5000;
app.listen( port, () => console.log(`server at http://localhost:${port}`));
I am using postman and I dont have cURL installed for some reason.
the postman just show this:
431 Request Header Fields Too Large
The server is unwilling to process the request because either an individual header field, or all the header fields collectively, are too large. Proposed in an Internet-Draft.
THE app is suppose to register the new user and send the new users info to the MongoDB, but when i attempt to register the user it throws an error of 500 internal error. the console says the error is in the user file, the terminal say this is the error, Proxy error: Could not proxy request /api/users from localhost:3000 to https://localhost:5000.
[1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (EPROTO).
I've already tried changing the proxy in the packet.json by giving it a different path and target but its not working. maybe i'm overlooking something. enter code here
import React, { useReducer } from 'react';
import axios from 'axios';
import AuthContext from './authContext';
import authReducer from './authReducer';
import {
REGISTER_SUCCESS,
REGISTER_FAIL,
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_ERRORS
} from '../types';
const AuthState = props => {
//initial state
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: null,
user: null,
loading: true,
error: null
};
const [ state, dispatch ] = useReducer(authReducer, initialState);
// load user
const loadUser = () => console.log('load user') ;
// register user
const register = async formData => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
try {
const res = await axios.post('api/users', formData, config);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data
});
} catch (err){
dispatch({
type: REGISTER_FAIL,
payload: err.response.data.msg
});
}
}
// login user
const login = () => console.log('login') ;
//logut
const logout = () => console.log('logout') ;
// clear errors
const clearErrors = () => console.log('clearErrors') ;
return (
<AuthContext.Provider
value= {{
token: state.token,
isAuthenticated: state.isAuthenticated,
loading: state.loading,
user: state.user,
error: state.error,
register,
loadUser,
login,
logout,
clearErrors
}}>
{props.children}
</AuthContext.Provider>
);
};
export default AuthState;
//this is my server.js file with the routes
const express = require('express');
const connectDB = require('./config/db')
//connect MongoDB
connectDB();
const app = express();
//init middleware
app.use(express.json({extended: false}));
app.get('/', (req, res) => res.json({ msg: 'hello welcome'})
);
//define routes
app.use('/api/users', require('./routes/users'));
app.use('/api/auth', require('./routes/auth'));
app.use('/api/contacts', require('./routes/contacts'))
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`server is working on ${PORT}`))
// this is mongoDB code
const mongoose = require('mongoose');
const config = require('config');
const db = config.get('mongoURI');
const connectDB = async () =>{
try{ await
mongoose.connect(db, {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false
});
console.log('mongo connected..')
} catch (err){
console.log(err.message);
process.exit(1)
}
};
module.exports = connectDB;
// this the users file where the console is throwing the 500 internal error.
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../models/User')
// This route Post request to api/users,
// description register a user,
// access to public to register an become a user
router.post('/', [
check('name', 'Name is require').not().isEmpty(),
check('email', 'please include email').isEmail(),
check('password', 'enter a password with atleast 6 characters'
).isLength({min: 6})
],
async (req, res) =>{
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({ errors: errors.array()});
}
const { name, email, password } = req.body;
try{
let user = await User.findOne({email});
if(user){
return res.status(400).json({msg: 'user already exist'})
}
user = new User({
name,
email,
password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
// object to send in the token
const payload = {
user: {
id: user.id
}
}
jwt.sign(payload, config.get('jwtSecret'), {
expiresIn: 36000
}, (err, token) => {
if(err) throw err;
res.json({token});
});
} catch (err){
console.log(err.message);
res.status(500).send('server error')
}
});
module.exports = router;
I figure out the problem!!!
I had an unexpected token in my users file that simple colon was interfering with the code