Next.js CORS blocking using Vercel - reactjs

This is not only a question, also an answer to my problem which took me a lot to resolve, I believe some devs will find it useful.
Let's start with some basic info:
The client app is using NextJs.
The server app is using NestJs deployed using the Vercel service.
Everything works fine in localhost, but when deployed the requests are always blocked by the CORS.
The server app deployment config (vercel.json) is the following:
{
"version": 2,
"builds": [
{
"src": "src/main.ts",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "src/main.ts",
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
]
}
]
}
In the server app, I enabled the CORS in the main.ts file:
app.enableCors({
allowedHeaders: '*',
origin: '*',
credentials: true,
});
Using any client I used (NextJs, Angular and even Insomnia and Postman) it shows that the CORS are set to accept any origin, still it's still blocking the requests.

The answer is not related to NextJs or NestJs but only to the vercel deployment config which needs to accept the OPTIONS type of HTTP request, the correct vercel.json file should look like this:
{
"version": 2,
"builds": [
{
"src": "src/main.ts",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "src/main.ts",
"methods": [
"GET",
"POST",
"PUT",
"PATCH",
"OPTIONS",
"DELETE"
]
}
]
}
Unfortunately, I didn't find this info in any docs I looked in, it only came up since HTTP requests of type OPTIONS are being used in the CORS mechanism.

Besides applying the CORS config for vercel, described here, you will also need your vercel lambda function to return a 200 status code for request using the OPTIONS method.
Please also that your vercel config needs to allow any custom header that you may be using when querying the endpoint. Lets say your GET request includes a header X-UserSession, such header should be allowed by CORS config as:
{ "key": "Access-Control-Allow-Headers", "value": "X-UserSession" }

Related

Firebase storage upload from Nextjs throws Cross Origin Request Blocked error on Firefox

I am learning to upload file to firebase storage using nextjs.
I am able to uploads file smaller than 1MB instantly but when I try to upload files with size > 1MB, I am getting CORS 400 error.
This is happening when using Firefox. Works fine with Chrome.
I have uploaded my sample repo here:
Github sample repo
This is the json for firebase configuration
[
{
"origin": [
"*"
],
"method": [
"GET",
"POST"
],
"responseHeader": [
"Content-Type",
"Access-Control-Allow-Origin"
],
"maxAgeSeconds": 3600
}
]

Fix CORS issue on react-pdf

I am trying to fetch pdf from s3 links and display in the react app. I am using react-pdf for it. but when react-pdf makes api call to fetch the pdf I am getting this error
Access to fetch at '...' from origin '...' 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.
on React app I have also added this,
source={{
header: {
'Access-Control-Allow-Origin': '*',
},
}}
This message tell us that back-end not allow to your client side make HTTP request.
So you have to config your fetch to make a CORS request, but I couldn't find any way to config react-pdf to do it for you, you may have to cache it and then render it...
However to access Amazon S3 Link you have to manage Bucket configuration options to allow CORS fetch requests like this(source):
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"http://www.example1.com"
],
"ExposeHeaders": []
},
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"http://www.example2.com"
],
"ExposeHeaders": []
},
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
For more information Using cross-origin resource sharing (CORS) from Amazon S3 user guid.

POST 403 forbidden CORS response when uploading an image to AWS S3 bucket ReactJS

Hello so I am trying to upload images to AWS S3 from my React application using an NPM package called react-s3. I am using an AWS Educate account and have setup the access and secret key correctly. After I select the image and console log the output it gives me a 403 forbidden error as follows.
POST https://shopkartimages.s3.amazonaws.com/ 403 (Forbidden)
Response {type: "cors",
url: "https://shopkartimages.s3.amazonaws.com/",
redirected: false,
status: 403, ok:
false, …}
body: (...)
bodyUsed: false
headers: Headers
__proto__: Headers
ok: false
redirected: false
status: 403
statusText: "Forbidden"
type: "cors"
url: "https://shopkartimages.s3.amazonaws.com/"
__proto__: Response
My bucket policy is as follows :
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Permissions",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "arn:aws:s3:::shopkartimages/*"
}
]
}
My CORS configuration in S3 is as follows:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"x-amz-server-side-encryption",
"x-amz-request-id",
"x-amz-id-2"
],
"MaxAgeSeconds": 3000
}
]
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3Permissions",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": "arn:aws:s3:::shopkartimages/*"
}
]
}
Your bucket policy only allow Get & List operations.
And uploading a file is a PUT operation.
I ran into this exact same problem with react-s3. I finally abandoned it in favor of AWS SDK which works fine for me (even in react). Here's what it took.
First install aws-sdk:
$ npm install aws-sdk
Then replace whatever you were doing with react-s3 with this:
import AWS from 'aws-sdk';
AWS.config.update({ region:region, credentials: new AWS.Credentials(secret_id, secret_access_key)});
var s3 = new AWS.S3({apiVersion: "2006-03-01", params: { Bucket: bucketName }});
let upload_params = {Bucket: bucketName, Key: file.path, Body: file};
let upload = new AWS.S3.ManagedUpload({params: upload_params});
let promise = upload.promise();
promise.then(
function(data){console.log("Successfully uploaded:", file.path);},
function(err){console.log("Failed to upload", file.name, "with error:", err.message);}
);
Here's my CORS stuff from S3 Bucket Permissions:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"HEAD",
"GET",
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
]
}
]
Also, public access is blocked and I'm not messing around with custom bucket policies.
Hope this helps someone else dealing with these CORS/S3/react nightmares.

What best solution for prevent browser cache file in react

My problem is
when I deploy new version react web to production
some user browser display old version from previous deploy
My user have to press ctrl+f5 for clear cache browser then I think which bad solution
please suggest best solution for me thx bro.
This could be because your web server is setting a cache control response header, which is set to a large value. Could you check the value in devtools?
A simple explanation of what cache control does is it tells the browser that the browser can use the cached resource upto n minutes. So only after n minutes will the browser send a new request for the resource.
Since you have a react app (a web app), the browser requests for index.html, and it will subsequently fetch the js bundle for your react app.
When you push an updated version, the browser doesn't know that there is an update. Since the index.html was cached, it continues to use it. Until the cache time expires, and then it will fetch again and this time it will get the latest js bundle.
Based on your server, you will need to figure out how to set the cache-control header for index.html to be of value no-cache. Here is an example of how I set it up in firebase hosting,
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
]
},
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"headers": [
{
"source": "/service-worker.js",
"headers": [{ "key": "Cache-Control", "value": "no-cache" }]
},
{
"source": "/index.html",
"headers": [{ "key": "Cache-Control", "value": "no-cache" }]
},
{
"source": "/static/**/*",
"headers": [
{
"key": "Cache-Control",
"value": "max-age=31536000"
}
]
}
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
Since create react app automatically configures the webpack build to generate static files with different hashes in the filename, it is fine to set a large cache value for it.
That occurs because, by default, the service workers do cache, so you should check your react project index.js file and check to see if services workers are registered. serviceWorker.register().
If it is registered then Unregister the service worker serviceWorker.unregister().
The above being quite drastic as a method, since it could affect your user experience what is recommended is that you configure your PWA to suit your particular caching needs. Follow this resource "https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker" for more about playing with service workers.
In case you need caching for your application, your backend sends appropriate response headers.

How to set "Access-Control-Allow-Credentials" in Firebase hosting

I've set up a Node Express application in Firebase Functions, and a React app in Firebase Hosting (similar to the template I built, with the exception that I've configured session cookies in express and I'm using Passport JS).
My firebase.json contains the following:
{
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/api/**",
"function": "app"
}
]
}
}
If I make a direct fetch request from the React app to the API using the full absolute API url, everything works hunky dory:
try {
const url = 'https://us-central1-[my-app-name]-app.cloudfunctions.net/app/api/v1.0/auth/status';
const response = await fetch(url,
{
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
}
);
json = await response.json();
console.log(json); // {"isAuthenticated":true}
} catch (error) {
throw error;
}
The API checks for the existence of a user in session and returns a response accordingly.
However, if I attempt to access the API through the rewrites proxy I've configured in the firebase.json file, using just the relative url /api/v1.0/auth/status then I still get a response (which confirms Firebase proxies the request appropriately), but the isAuthenticated flag is set to false, rather than true.
I assumed that this is because the proxied request is missing my valuable 'withCredentials' header, so I set this in the firebase.json file too:
{
"hosting": {
"public": "build",
"ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
"rewrites": [
{
"source": "/api/**",
"function": "app"
}
],
"headers": [
{
"source": "/api/**",
"headers": [
{
"key": "Access-Control-Allow-Credentials",
"value": "true"
},
{
"key": "Content-Type",
"value": "application/json"
}
]
}
]
}
}
However, this appears to have no effect. Is there something I'm missing?
Edit: On closer inspection I believe it's because the cookie header isn't being passed onto the functions app when Firebase proxies the request (the 'credentials' headers shouldn't be required as it's not cross-origin), so I believe there must be some way to tell Firebase to include cookies in the rewrite/proxied request?
You can include this code in your express configuration.
This would solve cors problem
// allow-cors
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
next();
});

Resources