express CORS withCredentials cookies issue when deployed on Heroku - node.js

I made an app including Vue.js client app and Node.js Express server app.
My client sents axios GET requests with cookies to the express server.
The problem is, the server deployed on Heroku doesn't get the cookies, although the local server works well.
It seems very weird because the server on Heroku actually gets the cookies when I test it with Postman.
const res = await axios.get(endpoint + '/api/user/auth', { withCredentials: true })
This is my client's axios request code.
const corsConfig = {
origin: true,
credentials: true
}
app.use(cors(corsConfig))
This is a part of the index.js file configuring CORS of the express server.
let auth = (req, res, next) => {
let token = req.cookies.x_auth
console.log(req.cookies)
console.log('token: ', token)
This is the part of a route getting cookies.
Local Vue.js client - Local express server => COOKIES
Local Vue.js client - Heroku express server => NO COOKIES
Deployed Vue.js client - Heroku express server => NO COOKIES
Postman request - Heroku express server => COOKIES
I don't even know whether it's a problem of the server or the client. All requests work just fine but getting cookies.

Related

Axios not receiving cookies in Heroku deployed MERN application

I have a Node/Express server deployed on Heroku that I am using to send httpOnly cookies to store JWTs. I have been using Axios to set the cookies while hosting my React app on port 3000 and the Express server on port 5000.
Axios Config in React App
const myAxios = axios.create({
withCredentials: true,
baseURL: "http://localhost:5000/",
});
index.js of Express App
app.use(cors({ origin: true, credentials: true }));
This has been working fine until I deployed my app to Heroku and switched my Axios config to use baseURL:http://app-name.herokuapp.com. I am now no longer receiving cookies (for both GET and POST requests). I still get the cookies if I visit http://app-name.herokuapp.com/get-cookie-endpoint directly in Chrome or in Postman. However, when I try calling myAxios.get('/get-cookie-endpoint) from my React app on localhost:3000, I no longer receive the cookie. I inspected the XHR request and I am still getting a Set-Cookie response header.
Any ideas? I have experimented with many different Axios and CORS settings but nothing seems to work.
Try adding sameSite = 'none'; in cookie object. I was having this issue and it worked for me.

Nuxt.js get status 400 from express API on production mode

I develop an app with Nuxt and Express API on my local mashine. Here is all working fine.
Its a sigle Nuxt app with axios. The Express API is single too.
Now I put the API and Nuxt app on my server Ubuntu (Plesk). Now the API + Nuxt app is running, when I open Nuxt pages without asyncData or async fetch, it works also fine. But when I open (on reload) a page with the asyncData request I get an error:
Server error
An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.
This is working:
request from Postman to online API (status 200)
go on page without asyncData and click on the link without reload (no SSR)
This is not working:
SSR -> open direct URL to page with asyncData from API (In the server Logs give the API a status code 400)
Here is my short testing code:
Express
const express = require('express')
const app = express()
const port = process.env.PORT || 5555
const cors = require('cors')
app.use(cors())
app.get('/public', (req, res) => {
res.send('response')
})
app.listen(port)
Nuxt.js
asyncData ({ $axios }) {
return $axios.$get(`https://api.domain.com/public`)
.then((res) => {
return { data: res }
})
}
the funny thing is that when I make a request to (https://jsonplaceholder.typicode.com/todos) the asyncData is working. Thats why I think it is a problem in my API

How to make API request from react client to express server running on the Heroku platform

Ive been trying to deploy a Twitch like application using react, redux, node media server and json server module to Heroku. However, I keep running into a issue when trying to connect my react client and express server via a api request, during production.
Im trying to make the actual request through my action creators and by using axios with a base url of http://localhost:4000, however that only works on my local machine.
const response = await streams.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
You can view my full repo at https://github.com/XorinNebulas/Streamy
You can also view my current deployed version of the site on Heroku at
https://streamy-app.herokuapp.com/
here is my api/server.js file. My express server will be watching on a random port equal to process.env.PORT, so I have no way of knowing how to make a network request via my action creators to that random port during production.
const path = require("path");
const cors = require("cors");
const jsonServer = require("json-server");
const server = jsonServer.create();
const router = jsonServer.router("db.json");
const middlewares = jsonServer.defaults({
static: "../client/build"
});
const PORT = process.env.PORT || 4000;
// Set default middlewares (logger, static, cors and no-cache)
server.use(cors());
server.use(middlewares);
if (process.env.NODE_ENV === "production") {
// Add custom routes before JSON Server router
server.get("*", (req, res) => {
res.sendFile(
path.resolve(__dirname, "../", "client", "build", "index.html")
);
});
}
// Use default router
server.use(router);
server.listen(PORT, () => {
console.log(`JSON Server is listening on port ${PORT}`);
});
I expected the request to go thru and load up some data from api/db.json, with a resquest url of https://streamy-app.herokuapp.com/streams but instead i got a request url of http://localhost:4000/streams, which of course leads to the CORS issue below
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:4000/streams. (Reason: CORS request did not succeed).
I would truly appreciate any suggestions, been working on this for days.
Alright looks like I figured it out. I simply went into streams/client/package.json and added
"proxy":"http://localhost:4000"
I then went into streams\client\src and deleted the api folder which contained my custom axios with a base url. using instead axios out of the box for my action creators
const response = await axios.get("/streams");
dispatch({ type: FETCH_STREAMS, payload: response.data });
};
Now while running locally in development mode, I'm able to make a request to http://localhost:4000/streams, but after deploying my node app to Heroku I successfully make a request over to https://streamy-app.herokuapp.com/streams
hope this helps someone with slimier issues.
First, you should know that Heroku doesn't allow to expose multiple ports, which means you should change the approach of multiple ports to something else (see this answer).
Second, the file client/src/apis/streams.js is hard-coded configured to send requests to http://localhost:4000/ - which is not a good idea.
Whatever approach you choose - even deploying to another host server - you will need to dynamically configure the API endpoint, per environment.
I would also recommend you to:
Change the way you deploy react, as explained here.
After doing the above, consider consolidating your API service with the static server, so that you don't need multiple ports, and then everything becomes easier.

React - Network Error when sending POST request only when on HTTPS

I have a web application where the front-end is done with React (create-react-app) and it is deployed on Heroku. The back-end is done with node.js/express and it runs on an Amazon EC2.
I don't have any problem getting the app to work when I deploy the front-end on localhost or on Heroku if I access it with HTTP as http://myapp.heroku.com. The problem arises when I access it with HTTPS (which is the default on Heroku) as https://myapp.heroku.com. When I do so and send a request to the node.js server on the Amazon EC2, I get the following error:
Error: Network Error
Stack trace:
createError#https://myapp.herokuapp.com/static/js/bundle.js:1555:15
handleError#https://myapp.herokuapp.com/static/js/bundle.js:1091:14
Here is the part in the front-end which send the request to the node.js server:
_deflateAscii(valueAscii){
axios.post('//My-EC2-Instance-Here.compute.amazonaws.com:80/deflate/ascii', {inflatedAscii: valueAscii}).then(res => {
this.setState(
{
inflatedAscii: valueAscii,
inflatedHex: res.data.inflatedHex,
deflatedBase64: res.data.deflatedBase64,
deflatedHex: res.data.deflatedHex
},
this._setTextBoxesValues
);
}).catch((err) => {
console.log(err)});
}
Here are the modules I use on the server-side:
const express = require('express');
const cors = require('cors');
const http = require('http');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cors());
And the part handling coming request from the front-end:
app.post('/deflate/ascii', function(req, res){
try{
console.log('request received');
var inflatedHexValue = convert.asciiToHex(req.body.inflatedAscii);
var deflatedBase64Value = deflate.asciiToBase64(req.body.inflatedAscii);
var deflatedHexValue = deflate.asciiToHex(req.body.inflatedAscii);
}catch(err){
console.log(err);
res.status(500).send(err);
}
response = {
deflatedBase64: deflatedBase64Value,
deflatedHex: deflatedHexValue,
inflatedHex: inflatedHexValue
};
res.end(JSON.stringify(response));
console.log('response sent');
});
When I get the Network Error on the front-end, the node.js server does not receive the request, but I have done some diagnostics with Wireshark and there is and handshake with the EC2 server, but the traffic ends there without any HTTP traffic:
TCP-traffic between https://myapp.heroku.com/ and My-EC2-Instance-Here.compute.amazonaws.com
Do I need SSL on the backend if the frontend is HTTPS? From this post I understood that it can also do without Do we need ssl certificate for both front end and backend?. This is just a course project anyway and there is only meaningless strings going back and forth.
When you visit your site over https in a browser, you need to disable blocking of mixed content (http and https). As a result your browser classifies the connection as not secure.
So yes it would be good to use SSL/TSL both for backend and frontend.
Alos did you try to use
res.json(response);
res.status(200).end();
or set the headers to application/json?
I recommend to put your res calls into the try catch block, because your res.end will be executed anyway.

Heroku node + react app: anchor tag auth request unhandled

I'm building a node + express server, with create-react-app to the frontend.
I used passportjs for auth routes handling, and all the stuff totally working on localhost ( backend on port 5000 and frontend on port 3000, with a proxy ).
When I deploy to Heroku, seems like the server can't recognize my auth routes and so heroku serve up static index.html.
If I test my APIs with Postman all seems to work ( I can see the html page for google oauth ), but with an anchor tag in my react app or manually writing the endpoint in the url, I can see only the same page reloading.
My server index.js:
const express = require('express')
const passport = require('passport')
const mongoose = require('mongoose')
const path = require('path')
// KEYS
const keys = require('./config/keys')
// MONGOOSE MODELS
require('./models/User')
mongoose.connect(keys.mongoURI)
// PASSPORT SETUP
require('./config/passport')
// CREATE THE SERVER
const app = express()
// EXTERNAL MIDDLEWARES
require('./middlewares/external')(app)
// ROUTE HANDLERS
require('./routes/authRoutes')(app)
// PRODUCTION SETUP
if (process.env.NODE_ENV === 'production') {
// express serve up production assets ( main.js, main.css )
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// START THE SERVER
const PORT = process.env.PORT || 5000
app.listen(PORT)
Flow:
LOCALHOST:
react app starts -> I click 'Google Login' -> GET request to "/auth/google" -> google oauth flow -> redirect to "/" and my react app reappears, the user is logged in.
HEROKU:
react app on my-app.herokuapp.com/ -> click on "Google Login" -> the page reloads, nothing happens. the user is not logged in.
Please guys, help me.
Thanks
This is a result of the service worker being installed by default to make your app a Progressive Web App
To determine if this is an issue for you, test your heroku production mode app in incognito mode. The request for /auth/google should now reach the server and behave as it does in development.
Once you determine it is an issue, you can remove the
import registerServiceWorker from "./registerServiceWorker";
from your /client/src/index.js file.
You browser cache may already contain an installed service worker so you may have to
clear browser cache on a user browsers
uninstall the server worker programmatically
import { unregister } from './registerServiceWorker';
....
unregister();
I had the same issues with same symptoms exactly.
For me the cause was a typo in the keys: in server/config/prod.js I had a line reading cookieKey: process.env.COOKIE_KEY but in Heroku Config Variables that variable was named cookieKey. Renaming it to COOKIE_KEY inside Heroku solved the issue.
If you've followed the Stephen Grider tutorial one thing I'm wondering: Is your passport.js file in config or services? I see you've written in index.js: require('./config/passport')
whereas mine in index.js is require('./services/passport')
may not be your solution to the google oauth flow hanging in production but may help.

Resources