I'm hosting my vueJS frontend on an apache server. Without running the apache just by calling "npm run serve" and visiting my page over http (https is enabled on express backend), I can successfully request to the backend.
When starting apache and visiting the page over https (self-signed SSL certificates), I can't send requests.
Firefox error:
Cross-source (cross-origin) request blocked: The same source rule prohibits reading the external resource on https://143.93.46.35:60702/user/login. (Reason: CORS request failed).
And chrome:
xhr.js:160 POST https://143.93.46.35:60702/user/login net::ERR_SSL_PROTOCOL_ERROR
I enabled https on my express backend like:
https.createServer({
key: fs.readFileSync('certs/apache-selfsigned.key'),
cert: fs.readFileSync('certs/apache-selfsigned.crt')
}, app)
.listen(nconf.get('port'), function() {
console.log(`App listening on port lalala! Go to https://localhost:3000/`)
});
Enabled cors in app.js like:
const cors = require('cors');
...
// Enable CORS (cross origin resource sharing)
app.use(cors({
credentials: true,
origin: true
}));
app.options('*', cors());
And the vue service which handles the axios calls is:
const apiClient = axios.create({
baseURL: `https://inf-education-47.umwelt-campus.de:60702`,
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default {
// user Endpoints
getUser (email) {
return apiClient.get(`/user/${email}`)
},
registerUser (user) {
return apiClient.post(`/user/register`, user)
},
loginUser (user) {
return apiClient.post(`/user/login`, user)
},
...
In apache I edited the vhost conf to enable cors like:
<VirtualHost *:80>
ServerAdmin webmaster#test.de
DocumentRoot /var/www/client/pvapp-client/dist
Header set Access-Control-Allow-Origin "*"
....
What can be the reason for the errors when hosting vue with apache over https?
Related
I'm calling a my express server in NextJS like this:
const { data } = await axios.post(
url,
body,
{
withCredentials: true,
}
);
and in the server I have this configuration:
app.use(
cors({
origin: "*",
credentials: true,
})
);
When I make requests using Nextjs in any browser I get CORS error no allow credentials.
I call the same endpoint in Insomnia and don't get any issue
Initial Problem
I work on a web application (react) that accesses data via an API. The API runs for development reasons on a docker container on my local machine. Simple GET requests (via axios) got me CORS complications (...has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.).
A bit of researching solved my problem by running a nginx reverse proxy in another container. I basically used this configuration for the nginx server.
New Problem
As I progress in building my application, I come to a point where I need to send the JWT to the API to access and alter some entries. Requests that need sending a JWT again get me CORS error messages.
The API checks the JWT signature (RS256 generated). I just have to forward it to the API server.
ALSO: simple curl requests with the JWT from the console are working.
Configuration
axios
const axiosConfig = {
responseType: "json",
withCredentials: false,
mode: "no-cors",
headers: {
'Access-Control-Allow-Origin': "*",
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
'Content-Type': 'application/json',
'Authorization': 'Bearer <JWT as string>',
},
};
const apiGetRequest = async (route, callback) => {
try {
const apiUrl = URL + route;
axios.get(apiUrl, {
axiosConfig
})
.then(res => {
callback(res);
})
.catch(function (error) {
console.log(error);
});
} catch (error) {
console.log(error);
}
}
nginx configuration
Docker Image for api
version: "3.9"
services:
db:
image: mariadb:latest
container_name: db
env_file:
- ./mariadb/.env
volumes:
- ./mariadb/create-schema-docker.sh /docker-entrypoint-initdb.d
- db-data:/var/lib/mysql
ports:
- 3306:3306
rest:
image: mds4ul/station-registry:latest
container_name: api
environment:
- DB_HOST=db
- CONTEXT_PATH=api
env_file:
- ./rest/.env
depends_on:
- db
ports:
- 80:8080
volumes:
db-data:
Questions
Why do I get CORS errors for requests where a jwt is needed and not for requests that do not require one?
Which part do I have to change to make this work?
So answer another question to an embarrassing easy problem of mine.
I switched to an express.js proxy server with the following configuration:
const express = require('express')
const app = express()
const axios = require('axios')
const cors = require('cors')
var bodyParser = require('body-parser')
app.use(cors({
origin: '*'
}))
app.use(bodyParser.json())
require('dotenv').config()
const headers = {
"X-Authorization": <token>,
}
app.get(':endpoint([\\/\\w\\.-]*)', function (req, res) {
const endpoint = (process.env.API_BASE_URL).replace(/\/$/, "") + req.params.endpoint;
axios.get(endpoint, { headers }).then(response => {
res.json(response.data)
}).catch(error => {
res.json(error)
})
})
app.listen(3001)
I assume I just could not figure out my nginx configuration for this use case. So with express.js I can access now resources which need authorization.
I am trying to do an axios GET request in vue3:
vue.config.js
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: 'https://example-url.com/',
}
})
Request.js
const url = "http://localhost:8080/example/.../"
When sending the request I am getting the following error:
400 (Bad Request)
The origin of the 400 (Bad Request) is a missing SSL certificate, which I am getting asked for in the browser when accessing https://example-url.com/example/.../ without the proxy (results in CORS policy error).
Why am I not getting asked for a client certificate when accessing the api via the proxy?
How can I configure my request that I am getting asked for a client certificate?
Solution for appending SSL Certifcate in webPack devServer Proxy
module.exports = defineConfig({
transpileDependencies: true,
devServer:{
proxy: {
'^/api': {
target: {
protocol: "https:",
host: "base-url",
port: 443,
pfx: fs.readFileSync('pfxFile.pfx'),
passphrase: 'your-passphrase',
},
changeOrigin: true,
}
}
}
})
Request URL then needs to go to e.g. http://localhost:8080/api
I have a local (Angular) client running on port 4200 (http://localhost:4200) and a local (express) server on port 5000 (http://localhost:5000). Whenever I try to connect to my server, I get this message.
Access to XMLHttpRequest at 'http://localhost:5000/socket.io/?EIO=4&transport=polling&t=NU7H' from origin
'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here is the code to start my local server
#injectable()
export default class App {
app: express.Application;
constructor() {
this.app = express();
this.config();
this.bindRoutes();
}
// Middlewares config
private config(): void {
this.app.use(cors());
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true }));
}
bindRoutes(): void {
this.app.use('/', router);
}
}
Here is the code where I set up my socket
private _ioServer: SocketIO.Server;
initSocket(server: http.Server) {
this._ioServer = new SocketIO.Server(server);
this.connectChat(); // Chat namespace
this.connectStream(); // Game board streaming namespace
}
I tried with Postman, everything is working.
Thank you!
Any malicious site can take advantage of your cookies stored in the system called Cross-site request forgery
Any browser tries to prevent you from these attacks so they disable CORS.
Shorthand Fix [Not recommended] : There are many plugins out there you can use for your local testing that disables these checks on browser.
Proper Fix: Use an Express middleware to apply Access-Control-Allow-Origin: * in your header when response is returned back from the server.
Gist is that when browser sends the request to your server it will append Origin: http://localhost:3000 to the headers. Reacting to this request from browser, server should return a Access-Control-Allow-Origin header to specify which origins can access the server's resources.
You can be strict here to return Access-Control-Allow-Origin: http://localhost:4200 or open your gates by sending Access-Control-Allow-Origin: *.
Here is the quick code to have an express middleware:
const express = require('express');
const request = require('request');
const app = express();
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get('/jokes/random', (req, res) => {
request(
{ url: 'https://joke-api-strict-cors.appspot.com/jokes/random' },
(error, response, body) => {
if (error || response.statusCode !== 200) {
return res.status(500).json({ type: 'error', message: err.message });
}
res.json(JSON.parse(body));
}
)
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on ${PORT}`));
Source: https://medium.com/#dtkatz/3-ways-to-fix-the-cors-error-and-how-access-control-allow-origin-works-d97d55946d9
P.S, this is a very good read for your understanding of CORS.
In the index.js file of your middleware add:
app.use(cors())
I'm doing fetch from my frontend to my express backend. But express logs req.cookies as '' (empty). I'm using cookieParser.
Why is express not finding the cookie, even though the browser shows the cookies being sent?
Note: I'm using cookies forwarded by my load balancer, which does the authentication and sends the session over.
Frontend
fetch(`${MY_URL}/logout`, {
credentials: 'include',
})
NodeJS
const cookieParser = require("cookie-parser");
app.use(cookieParser());
app.get("/logout", (req, res, next) => {
console.log(req.headers) // see below
console.log(JSON.parse(JSON.stringify(req.cookies))); // logs {}
console.log(JSON.parse(JSON.stringify(req.signedCookies))); // logs {}
// do stuff with cookie
});
Headers
{
...
cookie: ''
}
Cookie in Headers is an empty string
Network tab:
Got this working. Eventually the solution was that the Load balancer automatically forwards these headers to the backend silently. For my /logout api, instead of trying to grab the cookies from the headers, I set them regardless. Something like this:
app.get('/logout', (req, res) => {
res.cookie("AWSELBSessionCookie", "", {
maxAge: -1,
expires: Date.now(),
path: '/'
}
res.setHeader("Cache-Control", "must-revalidate, no-store, max-age=0");
res.setHeader("Pragma", "no-cache");
res.setHeader("Expires", -1);
res.redirect("https://my-login-page.com");
})