JWT Auth Does Not Work Heroku

When I sign up or sign in on my nodejs application, I generate a jwt token but what happens after is I have an api that verifies that token but that api only works on postman and not heroku. I am unsure of why that is. It just gives me a 401 error.

auth.js


//check if user is authenticated
exports.isAuthenticated = async (req,res,next) => {
    const {token} = req.cookies;
    //make sure token exists
    if (!token) {
        return next (new ErrorResponse('You must log in to access this resource okay yeah', 401));
    }
    try {
       //verify token
       const decoded = jwt.verify(token, process.env.JWT_SECRET);
       req.user = await User.findById(decoded.id);
       next();
    } catch (error) {
        return next (new ErrorResponse('You must log in to access this resource okay dude', 401));
    }
}

Did you add the JWT_SECRET variable to the Heroku config vars?

Yes I did add that variable to the config variables. I seem to get a cors error that prevents it

** No ‘Access-Control-Allow-Origin’ header is present on the requested resource.**

but I thought I had code to deal with it.

index.js

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    next();
  });

Try using the cors package and see if that works. I assume your middleware is running before all the routes?

I have the middleware before my routes.

index.js


const express = require("express");

const app = express();
const PORT = process.env.PORT || 8500
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const errorHandler = require("./middleware/error");
const cors = require('cors');

//setting cors
const corsOptions = {
//my origin
    origin: '*'
  }



//Import Routes
const Routes = require('./routes/routes');

dotenv.config();

//middleware
app.use(cors(corsOptions));
app.use(express.json());
app.use(helmet());
app.use(bodyParser.json());
app.use(morgan("dev"));
app.use(cookieParser());
app.use("/api", Routes);


//welcome message 
app.get('/', (req,res) => {
    console.log("Welcome to the API.")
});


app.get('/greeting', (req,res) => {
    res.json({greeting: 'Hello there'})
});


mongoose.connect(process.env.MONGO_URL, {useNewUrlParser: true, useUnifiedTopology: true}).then(() => {
    console.log("MongoDB Connected")
})
.catch((err) => console.log(err));



app.listen(PORT, ()=> {
    console.log("Backend server is running!")
})

Okay so it says I need to add a “no-cors” method to the fetch method I have which is in my frontend but I am not sure how to do it and get it working.

Original

useEffect(()=>{
    fetch(process.env.REACT_APP_USER)
    .then(res => {
      return res.json()
    })
    .then(result=>{
      console.log(result);
      setProfile(result.user);
    })
    .catch(error => {
      console.log(error);
    })
},[]);

My attempt

useEffect(()=>{
    const data = fetch(process.env.REACT_APP_USER, {
      mode: 'no-cors'
    })
    .then(res => {
      return res.json()
    })
    .then(result=>{
      console.log(result);
      setProfile(result.user);
    })
    .catch(error => {
      console.log("this is the error for getme" ,error);
    })
    return data.json()
},[]);

You shouldn’t use the no-cors mode, it returns an opaque response.

Fetch Standard

no-cors”: Restricts requests to using CORS-safelisted methods and CORS-safelisted request-headers. Upon success, fetch will return an opaque filtered response.

Fetch Standard

An opaque filtered response is a filtered response whose type is "opaque ", URL list is the empty list, status is 0, status message is the empty byte sequence, header list is empty, and body is null.


Not sure why you can’t fetch from your own API. Does commenting out the helmet middleware do anything?

Is the URL you are fetching against an HTTPS URL?

Is your frontend on Netlify? (I seem to remember you moving it to that).

You might try using

But I really do not think that should be needed if the backend is set up correctly and you are not fetching from HTTPS to an HTTP endpoint

I commented out the helmet and that did not work. I also tried a _redirect file which is basically like the netlify.toml file and that did not succeed.

(still get the same cors error : No ‘Access-Control-Allow-Origin’ header is present on the requested resource.).

All the urls I am doing a request to on heroku are https. My frontend is on netlify, and I am fetching from an https to an https endpoint.

Any other suggestion would be greatly appreciated.

Do you have a repo for this so we can see all the code?


I assume this has to do with using a cookie for JWT.

  1. Add the sameSite option to the cookie res.
res
  .cookie('token', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'none',
  })
  .send();
  1. Add the origins to cors (not *) and set credentials: true (the URL should not have a trailing slash)
app.use(
  cors({
    origin: [
      "http://localhost:3000",
      "https://yourfontend.netlify.app",
    ],
    credentials: true,
  })
);
  1. Set credentials: 'include' in the fetch options (or use Axios with defaults axios.defaults.withCredentials = true)

Article

Here is an example repo I found you can look at. I tested it with Heroku and Netlify and it works for me.

https://github.com/jgbijlsma/mern-auth-template-tutorial

I am still getting the same cors error. I will provide my github repo though.