Fix CORS issue on react-pdf - reactjs

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.

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
}
]

Next.js CORS blocking using Vercel

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" }

Unable to upload images to AWS S3 from React App

I want to upload images to AWS S3 from my React app directly using aws-sdk.
I have setup my S3 bucket with the following policies -
Bucket Policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:DeleteObject",
"s3:GetObject",
"s3:ListBucket",
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::<my-bucket-name>",
"arn:aws:s3:::<my-bucket-name>/*"
]
}
]
}
CORS Policy:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"HEAD",
"GET",
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag"
]
}
]
In my React app I'm using aws-sdk to upload images to S3. I have the following function -
export const uploadToS3 = (file: any) => {
AWS.config.update({
accessKeyId: S3_ACCESS_KEY,
secretAccessKey: S3_SECRET_KEY,
});
const bucket = new AWS.S3({
params: { Bucket: S3_BUCKET_NAME },
region: S3_REGION,
});
const params: any = {
ACL: "public-read",
Body: file,
Bucket: S3_BUCKET_NAME,
Key: file.name,
};
bucket
.putObject(params)
.on("httpUploadProgress", (e) => {
console.log(Math.round((e.loaded / e.total) * 100));
})
.send((error: any) => {
if (error) console.log(error);
});
};
I still get a CORS error -
Access to fetch at 'https://tribeone-nonceblox.s3-ap-south-1.amazonaws.com/' 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.
What should I do?

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.

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