Uploading a video to the presigned URL from Frontend - javascript

I have used my backend code to generate the presigned URL and then used that URL to upload a video that was recorded during the session. I am using the below piece of code in the frontend(React JS) to upload the video the preflight seems to fail with 403 Forbidden and the post request fails with cors error. Please find below the details:
Code used:
static async uploadVideoToS3(url, body) {
try {
const myHeaders = new Headers({ 'Content-Type': 'video/mp4', 'mode': 'no-cors' });
const response = fetch(url, {
method: 'POST',
headers: myHeaders,
body: body
});
return response;
} catch (error) {
toast(error);
console.log(error);
}
}
Console error:
Access to fetch at 'https://xxxxxxxxxx' from origin 'http://localhost:5000' 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.
Note: Changed the presigned URL to xxxxxxxxxx to avoid leaking the details in the post here.
Could the issue be that I am running all this on localhost? Or Is the CORS Configuration on the AWS S3 Bucket causing this issue? or Is there any header missing in my request?
I found a post that had a similar issue: Getting 403 (Forbidden) when uploading to S3 with a signed URL where the OP responded that the issue was resolved but they never mentioned the resolution.

Try adding proxy to package.json file and add the url of the server you're sending your request to, In your case localhost:5000
"proxy": "http://localhost:5000"
Then restart your app with npm start and change the url in your component, if you are doing it like
const res = fetch('https://localhost:5000/api/user')
then change it and do it like below
const res = fetch('/api/user')
If the above solution doesn't work then there might be a problem with your backend.

I thought so too that as I was trying to hit the URL from local which isn't served on a secure host (HTTP) was causing the issue. So I deployed the app on a dev environment but faced the same issue. After some research, I was able to fix the issue. It seems that I needed to modify the CORS configuration of the S3 Bucket that I was trying to generate the pre-signed URL from.
Before generating the pre-signed URL, I added the below piece of code which changes the CORS configuration of the S3 bucket and since I was accessing it from my local as well I have put the Allowed Origins as * for now but before moving to production, I will change it to the prod URL.
//passing AWS credentials
BasicAWSCredentials awsCreds = new BasicAWSCredentials(accessKey, secretKey);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(clientRegion)
.build();
//Creating CORS List to update the CORS Configuration
List<String> allowedHeaders=new ArrayList<String>();
allowedHeaders.add("*");
List<AllowedMethods> allowedMethods=new ArrayList<AllowedMethods>();
allowedMethods.add(0, AllowedMethods.GET);
allowedMethods.add(1, AllowedMethods.PUT);
List<String> allowedOrigins=new ArrayList<String>();
allowedOrigins.add("*");
List<String> exposedHeaders=new ArrayList<String>();
exposedHeaders.add("GET");
exposedHeaders.add("PUT");
CORSRule cors = new CORSRule();
cors.setAllowedHeaders(allowedHeaders);
cors.setAllowedMethods(allowedMethods);
cors.setAllowedOrigins(allowedOrigins);
cors.setExposedHeaders(exposedHeaders);
cors.setMaxAgeSeconds(3600);
//Assigning CORS List to CORS Configuration
BucketCrossOriginConfiguration CORSConfiguration = new BucketCrossOriginConfiguration();
CORSConfiguration.withRules(cors);
//Updating CORS Configuration
s3Client.setBucketCrossOriginConfiguration(bucketName, CORSConfiguration);
Alternatively, you can modify the CORS from the frontend/other languages as well, reference:
Javascript: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putBucketCors-property
Other Languages: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html#API_PutBucketCors_SeeAlso

Related

CORS: response to preflight request doesn't pass access control check - How to solve it on localhost?

I am quite a beginner with JavaScript and I am trying to write a script that checks whether a website, let's say https://example.comreturns 404 status code or 200, and depending on the result, I'll access it or not. I am doing this on front end side. I don't have a server side, as the website is a static one that does not use a database.
I am doing this using XMLHttpRequest.
url = $("#foo").attr("href")
function UrlExists(ur)
{
var http = new XMLHttpRequest();
http.open('GET', ur, true);
http.setRequestHeader("Access-Control-Allow-Origin", "http, https");
http.setRequestHeader("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTONS");
http.setRequestHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
http.send();
console.log(http.status);
}
UrlExists(url)
The problem is when I run this script, the following Exception is being thrown:
Access to XMLHttpRequest at 'http://example.com' from origin 'null' 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.
From what I read so far, it is rather CORS issue than JavaScript and I could not find a solution so far.
Can anybody help me with this issue and explain me why?
I have checked other questions on SO and so far, I did not find a working solution. I am open to other solution too if there are any. Thank you so much!
I much appreciate your time!
UPDATE 1:
Unfortunately, I am still struggling with this issue. I've read a lot about CORS policy, the problem is that I can't get how I should I can safely allow headers to be sent through request from my server to another one.
The resources are: an HTML page and some JS code in it. As I have mentioned above, I am trying to send a request from my site to another one to check the status of that website, and if 404 pops, I want to redirect my user.
You need to set the CORS header on your web server. It is disabled by default for security reasons.
For example, in Nginx, you may do
add_header Access-Control-Allow-Origin example.com;
In case you are using a hosting service that does not allow webserver config modification, you may add the required headers to .htaccess file in your as shown under. In other words, place it in the root of your project where you have your index.html. Also, change the permissions to 644.
Header add Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Methods: "GET,POST,OPTIONS,DELETE,PUT"
References:
https://stackoverflow.com/a/20082724/2777988
https://blog.container-solutions.com/a-guide-to-solving-those-mystifying-cors-issues
I'm using Flutter and Nodejs (in HEROKU), this worked for me:
FLUTTER:
//FLUTTER
...
final headers = <String, String>{
'Content-Type': 'application/json',
"Access-Control-Allow-Origin": "*",
};
final resp = await http.post(//here we make the req
Uri.parse(url),
body: convert.jsonEncode(body),
headers: headers,
);
///
SERVER NODEJS IN HEROKU:
///SERVER NODEJS IN HEROKU
const express = require('express');
const cors = require("cors"); //this is a library to config easily cors
const app = express();
app.use(express.json());
app.use(cors({ origin: true })); // enable origin cors
app.post('/',async(req,res)=>{
...
///
Then i solved mixed content (with heroku), and cors problem

Cannot call Apache Airflow REST API using JavaScript Fetch API (CORs Error)

Working with Apache Airflow REST API, and having issues with CORS.
When calling the endpoint using the fetch API in JavaScript I get the following error:
Access to fetch at 'my_url/api/v1/dags/example_bash_operator/tasks' from origin 'my_url' 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.
This is how I am calling it:
let url = "my_url/api/v1/dags/example_bash_operator/tasks";
let username = 'my_username';
let password = 'my_password';
let headers = new Headers();
headers.set('Authorization', 'Basic ' + btoa(username + ":" + password));
fetch(url, {
headers: headers,
method: 'GET',
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
I also tried adding mode: 'no-cors' but just get the "unexpected end of input" error.
For some background, the following works fine:
starting the airflow webserver and scheduler
accessing the airflow UI
accessing the SwaggerUI authenticating Swagger and calling the REST endpoints with this tool
calling my_url in the address bar of a new browser tab (returns the expected JSON)
I have set the auth_backend in airflow.cfg:
auth_backend = airflow.api.auth.backend.default
Although with the latest REST API version I don't think this makes a difference since everything is set to deny.
I have also set the access control headers in airflow.cfg as described in the docs:
access_control_allow_headers = origin, content-type, accept
access_control_allow_methods = POST, GET, OPTIONS, DELETE
access_control_allow_origin = my_url
...and also tried with wildcard for the access_control_allow_origin:
access_control_allow_origin = *
So the REST calls work fine through Swagger and through the browser address bar, but I cannot call it with fetch using JS. Note that the JS is in an index.html file on the same server (and same root directory) as the airflow files.
The described behavior makes sense, since CORS is used by the browser to prevent attacks from scripts of different resources.
You are still able to fetch via Swagger, Postman or other tools, even through the browser via address bar. But if the policy does not allow to fetch from a different origin, then the browser prevents fetching from your script, which is probably served on a different port. Origin contains host and port.
Your main issue, I cannot help with at the moment.
I've faced the issue of not being able to set the origin policy within the Airflow 2.0 server/API through the (docker-compose) environment variable AIRFLOW__API__ACCESS_CONTROL_ALLOW_ORIGIN.
Maybe it's related to your issue, since I can see from the url of your question (containing the v1), that you're are also using Airflow 2.x.
By the way, the message from chrome is CORS error: Preflight Missing Allow Origin Header, referring to the question in the comments of the original question.

Keycloak Introspection Endpoint

I'm trying to access to introspect endpoint in my Keycloak server /openid-connect/token/introspect from my front app, but I get next error:
Access to fetch at 'http://localhost:8180/auth/realms/backoffice/protocol/openid-connect/token/introspect' from origin 'http://localhost:8080' 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.
Using Postman, curl or Node app this request works fine, but from my front-app using fetch method thows this error. I'm not sure it's possible query for introspect endpoint from front-app in the browser or if it's only possible from server app.
Other endpoints like:
openid-connect/token:
openid-connect/userinfo:
Works fine using the Postman JS code.
Keycloak config
My client in Keycloak has set up Web Origins * and Access Type confidential.
Client Code
My front app is simply the Postman code JS, and I deploy it using node http-server.
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("client_id", "my-client");
urlencoded.append("client_secret", "my-secret");
urlencoded.append("token", "eyJ...oCA");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:8180/auth/realms/backoffice/protocol/openid-connect/token/introspect", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
Header Response
The header response in userinfo endpoint comes with Access-Control-Allow-Origin and Access-Control-Allow-Credentials but is not present in introspect endpoint.
From the looks of it, the Keycloak server prevents the CORS headers to be set for the introspection endpoint. This could be a bug or by design. I tried it and I get the same error.
If you really want to access the introspect endpoint from the web app, you could set up a NGINX reverse-proxy in front of your Keycloak server and use it to add the missing headers.
That being said, according to oauth.com you should not leave the introspection endpoint available to the public, which is what you are currently doing since anyone can retrieve the client id and secret from your web app.
If the introspection endpoint is left open and un-throttled, it presents a means for an attacker to poll the endpoint fishing for a valid token. To prevent this, the server must either require authentication of the clients using the endpoint, or only make the endpoint available to internal servers through other means such as a firewall.
This could explain the decision not to allow CORS.
Another thing, it looks like you forgot to set the token_type_hint check out this stackoverflow post for more information.

Microsoft Graph CORS preflight error on file download

Context:
I am trying to download files into a buffer for AngularJS application in order to forward the file to the backend for storing on the server (backend is not under my control) therefore I need to get file data into Blob which then gets uploaded my our own servers.
Issue:
Microsoft graph gives me their recommended #microsoft.graph.downloadUrl property in the JSON file which retrieves a list of all files in the currently selected folder. As I use it to download the file itself I get hit with Access to XMLHttpRequest at [the URL from #microsft.graph.downloadUrl] from origin 'http://localhost:8080' 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.
My code:
const req = {
method: "GET",
url: file.item.downloadLink, // #microsoft.graph.downloadUrl
headers: {
Authorization: `Bearer ${this.token}`
},
eventHandlers: getEventUploadEvenHandlers(file), // update download progress bar
responseType: "blob"
};
const ret = await this.$http(req);
My research:
I looked through this article from 5 years ago: https://github.com/microsoftgraph/microsoft-graph-docs/issues/43
I read the entire article about CORS and files here: https://learn.microsoft.com/en-us/onedrive/developer/rest-api/concepts/working-with-cors?view=odsp-graph-online
Of course, I have read the documentation: https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0&tabs=http
Nothing has given me an answer to why would the issue persist
If you have any experience with this issue or notice something you think I missed I would be very grateful.
Thank you for any help
So basically my whole approach was wrong.
I deduced from other cloud services that Microsoft Graph would return JSON with data of the file.
MICROSOFT RETURNS THE FILE ITSELF
Therefore fetch or a very simple request without any headers required is enough to get the file and then with .blob() or responseType: 'blob' you get a blob from the response.
(await fetch([#microsoft.graph.downloadUrl])).blob() // returns Blob promise

CORS issue when calling a localhost API hosted on one port from another port

I have a localhost Rest API POST query hosted using Docker at port 8501: http://localhost:8501/v1/models/model:predict. I have an HTML file which runs with a JavaScript script and it is hosted at http://127.0.0.1:8887/ using WebServer for Chrome. I am able to call global Rest API POST queries from my HTML-JS files and my local Rest API works fine from POSTMAN. But I am unable to call my API from my HTML-JS files.
Below is my JS file:
function foo() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Access-Control-Allow-Origin", "*");
myHeaders.append("Access-Control-Allow-Methods", "POST");
var raw = JSON.stringify({"instances":[[0]]});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("http://localhost:8501/v1/models/model:predict", requestOptions)
.then(response => console.log(response.text()))
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
I get the below error:
Access to fetch at
'http://localhost:8501/v1/models/model:predict' from origin
'http://127.0.0.1:8887' 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.
Can anyone please help me?
You seem to have understood CORS slightly "backwards" -- the Access-Control-Allow-Origin and Access-Control-Allow-Methods headers are specified on HTTP responses, not requests. This obviously implies that it's the HTTP server that sets them, not the client.
It would make for a terrible cross site security model if a script of arbitrary origin could effectively dictate to the HTTP server what kind of requests and from which origins the latter must accept.
It's the HTTP service that ultimately controls access by specifying appropriate headers in the responses it serves, and the user agent validates the cross origin request where it refuses to proceed if the server didn't indicate it allows requests from the different origin the script was served from -- the response will be discarded and an error will be thrown.
In short, you need to add the headers to the responses your REST service at localhost:8501 generates, instead of specifying them for requests your client side script creates where they don't do anything.
Your server is missing header Access-Control-Allow-Origin in response, as it is responsible what to allow or not. See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Categories

Resources