Based on what i read and tested on basic javascript clients i can pass extra headers in my Angular Client which will then be avail on my NodeJs server in the
socket.handshake . But i am not sure what i am missing or what i am doing wrong since below code does not create
async socketInit() {
this.client = io(`${environment.socketUrl}`, {
transportOptions: {
polling: {
extraHeaders: {
Authorization: "Bearer authorization_token_here"
}
}
}
});
await new Promise((res) => {
this.client.on('connect', () => {
this.isConnected = true;
this.socketId = this.client.id;
this.client.on('disconnect', () => this.isConnected = false);
res();
});
})
.catch((e) => console.log(`Socket.io error: ${e.message}`));
}
for some reason this causes the connect to fail as i can see in my debug console of the angular that socket.io has a TransportError
In my case, I was trying to connect to a web-socket server on port 5001, while my angular app was opened on port 4200. When I added extraHeaders to the client options, the browser started to throw the CORS error like this:
origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
The ports are not the same, and that's the cause of the cross-origin problem.
I've fixed it by setting my web-socket server port, the same as the web server, and opening the webpage on that port.
Related
I have my express server hosted on Heroku, while my react app is hosted on Netlify.
My server has a login route, and whenever I attempt to log in from the client hosted on netlify, I get the below CORS policy error;
Access to XMLHttpRequest at 'https://u-annon.herokuapp.com/api/users/login' from origin 'https://boisterous-churros-56908e.netlify.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
There's no cors error on the GET routes that fetches post, and I don't get this error on localhost, even when I connect the client on the localhost to the server on heroku, the cors setting seems to handle that well, which makes me think this has something to do with netlify hosting. I've been reading about the netlify.toml file, but I can seem to find anything that fixes this problem.
Can someone point me in the right direction pls?
This is my cors setting on the express server;
app.use(cors({
origin: ["https://boisterous-churros-56908e.netlify.app", "http://localhost:3000"],
credentials: true,
methods: "GET, POST, PUT, DELETE",
preflightContinue: true,
allowedHeaders: ['Content-Type', 'Authorization']
}))
This is the login post request from the client
const LoginSubmit = (e) =>{
const data = {
email: email,
password: password
}
const login = axios.post(`${url}/users/login`, encodeURI({...data}))
.then((res) => {
if(res.status === 200){
parseJwt(res.data)
setLoggedIn(true)
setLoading(false)
navigate('/profile')
}
else{
setLoginError("An error occured, pls try again")
return
}
})
.catch((error) => {
console.log(error)
setLoginError("Email or password entered is incorrect, try again or signup")
});
return login
}
I have two servers, frontend (Next.js) and backend (express.js api server).
Frontend server is running without any additions. But I have an nginx proxy for backend.
So far everything is good because they are not connected yet.
Frontend: is working as it should be.
Backend: I can make calls directly from the backend itself (by self origin).
When I make a fetch get call from my frontend server to the backend server, it normally gives a cors error because the origins are different.
For this, I set the backend server with cors:
// /src/middlewares/cors.ts
import cors from 'cors';
const whitelist = new Set(['http://192.168.1.106:3000', 'https://192.168.148.132']);
// frontend: http://192.168.1.106:3000
// backend: https://192.168.148.132
const corsOptions = {
optionsSuccessStatus: 200,
origin: (origin: any, callback: any) => {
console.log('origin: ' + origin);
if (whitelist.has(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
// credentials: true,
};
export default cors(corsOptions);
and
// /app.ts
import cors from './middlewares/system/cors.js';
.
.
// setup cors
app.options('*', cors);
app.use(cors);
.
.
After doing this, I reach my main goal. The frontend server can make call to the backend server.
output:
But this time I notice a problem. I can't send self request to backend anymore (by self origin).
When dealing with this I looked at the origins that came to the /src/middlewares/cors.ts file that I showed above.
for frontend:
for backend:
I am using self signed ssl in nginx for back server.
And there is not any cors relevant headers in conf.
How can i solve this situation?
(If I'm missing something, you can point it out in the comments.)
The Origin header is only set in cross-origin requests. If you call your backend directly, the Javascript value is undefined, and in this case you must not restrict anything. You could, for example, write
if (!origin || whitelist.has(origin)) {
callback(null, true);
}
I'm facing a preflight error when I try to call a cloud function of mine from my website. I implemented the cors module in my cloud function, and my request got the cors header authorizations
The cloud function :
const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
(request: any, response: any) => {
cors(request, response, async () => {
response.status(200).send('hello');
})
}
);
The website request :
fetch('FIREBASE_URL/CLOUDFUNCTION',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Headers': 'Authorization'
},
body: JSON.stringify(body), // body is a simple {"variable": "value"}
}
);
The error
Access to fetch at 'FIREBASE_URL/CLOUDFUNCTION' from origin 'MYWEBSITE' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
If you are getting a 403 Forbidden Error when trying to access your function via it's URL, you have a problem with your function's deployment, it's configuration or you have made a mistake in the URL.
Note: While I use "traditional" require statements here to match your example, I encourage you to use newer ES6+ JavaScript features (const, let, async/await, import, etc.) for any newly written functions.
Deploy using the latest firebase-tools version
Make sure you are deploying using the latest version of the firebase-tools CLI.
When v7.7.0 of firebase-tools released (Jan 15, 2020), the way Cloud Functions are invoked on the server changed so that functions could be invoked by only authenticated users. To be accessible to Firebase Users, these functions must be made public by explicitly granting the allUsers group the Cloud Function Invoker permission.
In v7.7.0 and later, this is done for you as part of deployment. However, if you deploy functions using an older version, you will need to configure this permission yourself or redeploy using a newer firebase-tools version.
Check the exported function name
Make sure the function you export is named what you expect once deployed.
In particular, pay close attention to when your function is exported as part of a function group either deliberately or accidentally. This often turns up when you've split your functions into multiple files. In the below code blocks, CLOUDFUNCTION gets exported as myFunctions-CLOUDFUNCTION and not just CLOUDFUNCTION as you may expect.
// myFunctions.js
exports.CLOUDFUNCTION = functions.https.onRequest(...);
// index.js (incorrect)
exports.myFunctions = require("./myFunctions.js");
// index.js (correct)
const myFunctions = require("./myFunctions.js");
exports.CLOUDFUNCTION = myFunctions.CLOUDFUNCTION;
Check the function's URL
Check the Cloud Functions URL you are using for typos. Function names in Cloud Functions URLs are case-sensitive.
The correct URL should follow the format:
https://<REGION>-<PROJECT_ID>.cloudfunctions.net/<EXPORTED_FUNCTION_NAME>
Example:
https://us-central1-fir-sandbox.cloudfunctions.net/echo
Handle CORS errors & stop processing
In your code example, you pass in the NextFunction without an error handler. While using { origin: true }, this is "fine", but you'll start running into trouble when you start restricting the origins you call your function from. This is particularly handy for preventing your functions being invoked directly by their URL (where origin would be undefined). Take a look at the documentation or the next section for more info.
const cors = require('cors')({ origin: true });
exports.CLOUDFUNCTION = functions.https.onRequest(
(request, response) => { // <-- don't use `: any` here, as you are disabling the built-in types provided by firebase-functions
cors(request, response, async (err) => {
if (err) {
// Denied by CORS/error with CORS configuration
console.error("CORS blocked request -> ", err);
response.status(403).send("Forbidden by CORS");
return;
}
response.status(200).send('hello');
})
}
);
Optional: Tighten the cors configuration
While you can reflect the Access-Control-* headers using the cors package, consider explicitly setting these server-side.
const { projectId: PROJECT_ID } = JSON.parse(process.env.FIREBASE_CONFIG);
const cors = require('cors')({
// during emulation, allow localhost & calling directly (i.e. no origin specified);
// at all other times, restrict to deployed hosting sites only
origin: process.env.FUNCTIONS_EMULATOR === "true"
? /^(https?:\/\/localhost:\d+|undefined)$/
: [`https://${PROJECT_ID}.firebaseapp.com`, `https://${PROJECT_ID}.web.app`],
allowedHeaders: ['Content-Type', 'Authorization']
});
exports.CLOUDFUNCTION = functions.https.onRequest(
(request, response) => {
cors(request, response, async (err) => {
if (err) {
// Denied by CORS/error with CORS configuration
console.error("CORS blocked request -> ", err);
response.status(403).send("Forbidden by CORS");
return;
}
response.status(200).send('hello');
})
}
);
This simplifies your client-side code:
fetch('FIREBASE_URL/CLOUDFUNCTION',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
}
);
Optional: Use Callable Functions
If your functions will require you to do actions on behalf of a user, you could make use of Callable Cloud Functions instead of the more bare-bones HTTPS Request functions. This version of a HTTPS Function handles CORS, authentication, and supports Promise-based returning of data.
Note: This will still require the function to be public as described above.
On the server side:
exports.CLOUDFUNCTION = functions.https.onCall(async (data, context) => {
if (!context.auth) {
// users must be logged in
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called while authenticated.'
);
}
if (data.variable === undefined)) {
throw new functions.https.HttpsError(
'invalid-argument',
'Parameter "variable" must be a string'
);
}
// you can return a promise here
// this sends back the JSON string "hello world"
return "hello world";
});
On the client side:
const callFunction = firebase.functions().httpsCallable('CLOUDFUNCTION');
callFunction(body)
.then(
(responseData) => {
// TODO: handle response
},
(functionError) => {
// TODO: handle error
}
);
My React App takes user input from frontend and send it to backend via Axios where the info will be used to search through MongoDB. My App works fine for a few input, like around 5-6, then it will stop working with no error and I have no idea what is wrong and how to fix it.
Here is an example of my problem, this useEffect will happen when page load and take param from the url and send it to backend (the param change depends on what link the user clicks on). It will then send the information to backend via axios and the Info is used to search through MongoDB and will dynamically generate the page's text. After the user clicks on around 5 different links tho, this will stop working and the page generated will be stuck on the last page it was generated dynamically although the params in the url still change. I added console.log to see if useEffect was activating or not, and everytime I click on a Link, the console.log will work when the page load. Any lead will help, thanks!
frontend runs on port 3000 and backend runs on 3001
useEffect(() => {
const idInfo = {id};
axios.post('http://localhost:3001/info', idInfo);
console.log("testing")
}, [])
useEffect(() => {
fetch("/info").then(res => {
if(res.ok) {
return res.json();
}
}).then(jsonRes => setGetId(jsonRes))}, [])
This is the backend
router.route("/info").post((req, res) => {
console.log(req.body)
const idInfo = req.body.id;
console.log(idInfo);
current_id = idInfo;
})
router.route("/info").get((req,res) => {
Disease.find({_id: current_id})
.then(foundId => res.json(foundId))
})
This way, when you fetch('/api/info') in development, the development server will recognize that it’s not a static asset, and will proxy your request to http://localhost:3001/api/info as a fallback. The development server will only attempt to send requests without text/html in its Accept header to the proxy.
Conveniently, this avoids CORS issues and error messages like this in development:
Fetch API cannot load http://localhost:3001/api/info. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
https://create-react-app.dev/docs/proxying-api-requests-in-development/
src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true,
})
);
};
useEffect(() => {
const idInfo = {id};
axios.post('/api/info', idInfo);
console.log("testing")
}, [])
useEffect(() => {
fetch("/api/info").then(res => {
if(res.ok) {
return res.json();
}
}).then(jsonRes => setGetId(jsonRes))}, [])
I have created an end point in csharp web api which returns some json data, it works fine on postman.
but when I try the same url on my react app I get the following error
React code
fetch('https://localhost:44391/agency')
.then(response => response.json())
.then(json => console.log(json))
Error
Access to fetch at 'https://localhost:44391/agency' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I followed this link Trying to use fetch and pass in mode: no-cors
and tried the following code
fetchData () {
var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
targetUrl = 'https://localhost:44391/agency'
fetch(proxyUrl + targetUrl)
.then(blob => blob.json())
.then(data => {
console.log(data);
return data;
})
.catch(e => {
console.log(e);
return e;
});
}
I get this error
GET https://cors-anywhere.herokuapp.com/https://localhost:44391/agency 404 (Not Found)
SyntaxError: Unexpected token N in JSON at position 0
Note
The steps from the link which I could not do was
git clone https://github.com/Rob--W/cors-anywhere.git - DONE
cd cors-anywhere/ - DONE
npm install - DONE
heroku create - COULD NOT DO THIS. DO I NEED HEROKU, I AM NOT SURE WHY
git push heroku master - NOT DONE YET
Your help is much appreciated
Thanks
P
Update
I have enabled CORS on my c# web api following the link https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#dp
section i followed was CORS with default policy and middleware
and my code is bellow
I have tried options.AddPolicy and options.AddDefaultPolicy but when I call from react app it still does not work
namespace React_NalONE_API
{
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
// options.AddPolicy(name: MyAllowSpecificOrigins,
// builder =>
// {
// builder.WithOrigins("http://localhost/*",
// "https://localhost/*");
// });
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://localhost/*",
"https://localhost/*");
});
});
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins);
});
}
}
}
You don't need Heroku if you're just trying to test it locally. I'm assuming that bit on the tutorial you used was just to deploy the application, in order to demonstrate it's functionality. You don't necessarily need to follow through with that bit to get everything to work.
The issue seems to be with CORS permissions, usually browsers don't let you make CORS requests unless the response from the origin that you're requesting contains the right CORS headers. I would check this out for some more context.
If enabling CORS is something you're looking to do, then you probably want to enable CORS in .NET (I'm assuming that you're using .NET - whatever framework you're using, there should be a way to enable CORS)