0

I am having a problem with cors when I call my netlify hosted nodejs express backend from my react frontend.

im am getting the following errormessage in my web browser:

Access to XMLHttpRequest at 'https://<my_api_domain>/api/forgotpassword' from origin 'localhost:8888' has been blocked by CORS policy: No 'Access-

Control-Allow-Origin' header is present on the requested resource."

I have tried a lot of solutions with setting headers in the respons from my backend, but nothing seams to work. In localhost everything works fine.

the main file, api.js, looks like this:

'use strict';
const express = require('express');
const serverless = require('serverless-http');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const router = express.Router();
router.use(express.json());
const apiLimiter = require('../middleware/ratelimiter');

//import modules
const youtube = require('./youtube');
const ip = require('./ip');
const sendgrid = require('./sendgrid');
const sendinblue = require('./sendinblue');
const login = require('./login');
const forgotPassword = require('./forgotpassword');
const register = require('./register');
const test = require('./test');

require('dotenv').config();
router.use(helmet());
router.use(morgan('combined'));
router.use(cors());


//this part was added in order to try to fix the cors error
app.use((req, res, next) => {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader(
        'Access-Control-Allow-Headers',
        'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization'
    );
    res.setHeader(
        'Access-Control-Allow-Methods',
        'GET, POST, PUT, DELETE, PATCH, OPTIONS'
    );
    next();
});

app.use(bodyParser.json());

router.use('/ip', ip);
router.use('/youtube', youtube);
router.use('/sendgrid', sendgrid);
router.use('/sendinblue', sendinblue);
router.use('/login', login);
router.use('/register', register);
router.use('/test', test);
router.use('/forgotpassword', forgotPassword);

app.use('/api', router);
// path must route to lambda

app.set('trust proxy', 1);

module.exports = app;
module.exports.handler = serverless(app);

The cors error only happens when I call the forgotpassword endpoint, which looks like this:

const express = require('express');
const router = express.Router();
//const { check, validationResult } = require('express-validator');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const connect = require('../functions/db');
const captcha = require('../middleware/captcha');
const sendMail = require('../functions/sendResetMail');

require('dotenv').config();
// get usermodel
const User = require('../models/User');
const Token = require('../models/resetPassword');

//@path: /forgotpassword
//@ public

router.post(
    '/',
    captcha,
     async (req, res) => {
        const { email } = req.body.data;
        console.log(email);
        connect();
        try {
            // See if user exists
            const user = await User.findOne({ email });
            if (!user) {
                console.log('no user'); //fjernes
                return res.status(200).json({
                    errors: [{ msg: 'If user Exists, an email will be sendt' }],
                });
            }
            const extToken = await Token.findOne({ userId: user._id });
            if (extToken) {
                await extToken.deleteOne();
            }
            const payload = {
                user: {
                    id: user._id,
                },
            };
            const secret = process.env.JWT_RESET_PASSWORD;
            const webToken = jwt.sign(payload, secret, {
                algorithm: 'HS256',
                expiresIn: 3600,
            });

            const salt = await bcrypt.genSalt(10);
            const tokenHash = await bcrypt.hash(webToken, salt);

            const token = new Token({
                userId: user._id,
                token: tokenHash,
            });
            await token.save();
            res
                .status(200)
                .header('Access-Control-Allow-Origin', 'http://localhost:60427')
           // several ways is tried of the above
                .json({ link: webToken, url: UrlLink });
            return;
        } catch (err) {
            res.status(400).json({ errors: [{ msg: err }] });
            return;
        }
    }
);

i have figured out that the cors error only appears if from either when I make a call to the database (not when connecting) og if I try to use crypt. If I don't make a cal to the database, or encrypt with bcryept, the cors error will not appear in my web browser.

PS: my frontend and backend is hosted separately, so the domain is not the same.

any help to figure this out will be much appreciated :)

tebendheim
  • 15
  • 2
  • 1
    Nowhere in your question do you mention the error message you're actually getting. That's vital information. – jub0bs Jul 24 '22 at 18:03

3 Answers3

0

I ran into this issue quite a bit I would make sure that you allow access at the very top of your server file so that its allowing access across all of your routes. Something like this

const app = express();

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use((_, res, next) => {
  res.set('Access-Control-Allow-Origin', '*'); // or 'localhost:8888'
  res.set('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
  res.set(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept'
  );
  return next();
}); // sets headers before routes

// routes start here
app.use('/ip', ip);
app.use('/youtube', youtube);

Make sure that if you're setting the response headers you're doing so BEFORE all of your routes. Most of the times I've struggled with CORS is because I was only setting it on some routes some of the time. This setup will ensure every route is g2g.

Kirk
  • 76
  • 4
  • Thank you @Krik :) that is a great point. Unfortunately the error still pops up after changing this in my api.js file :( – tebendheim Jul 24 '22 at 21:41
  • So looking at your code it looks like you're setting your headers on app.use but calling all of your routes with router.use. Every server I've ever stood up I called my routes in app.use not router.use. I just double checked a server I have running locally and all my end points are in the vein of app.use('/ip', ip); app.use('/youtube', youtube); – Kirk Jul 25 '22 at 02:03
  • Also while it probably doesn't have anything to do with your issue the app.use(express.json()) is a replacement for app.use(bodyparser.json()) and I usually call it just before I set the headers. – Kirk Jul 25 '22 at 02:07
  • thank you for the input @Krik. it is much appreciated :D i have removed the "app.use(bodyparser.json())" and moved the express.json part just above the set headers :) " I also changed router.use to app.use for all the routes. The error is still there though when i call the published api. in when all is hosted locally, it works :) – tebendheim Jul 25 '22 at 12:40
-1

You can mention the origins allowed as shown below

const cors = require('cors');

app.use(cors({
  origin: ['http://localhost', 'https://localhost/']
}));

or for all origins

app.use(cors({
    origin: '*'
}));
  • Thank you @Suman :) Unfortunately I'm still getting the same error when using the published api :( This is the error: **Access to XMLHttpRequest at 'https:///api/forgotpassword' from origin 'localhost:8888' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.** I added this in api.js `app.use( cors({ origin: '*', }) );` – tebendheim Jul 24 '22 at 14:41
-1

Solved!

Turnes out in this case, the error is misleading at best. I had forgotten to add the new environment variables (env. variables to connect to database, and to use JWT) to netlify for deployment. When that was done, it worked without changing any more code. PS: all code was changed according to the answers above.

Thank you to all the contributors :)

Why this resolved in a cors error in google chrome, I dont know. :)

tebendheim
  • 15
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Goutham J.M Jul 28 '22 at 09:17