How can I secure implement third-party API calls using JavaScript in a BigcCommerce store? - javascript

I want to make some API requests to the shipping carriers at the BigCommerce product page and I have some credential for that requests which I don't want to show in my JS code. According to the specific environment of BigCommerce I can't make any changes in back end code. I read a lot of similar questions and now have only one question.
Is it only one way to do that using my own API back end web-server which will store credential information and send POST request to the third party API? Then I will receive that information using a POST request via JS to my own API.
I have tried to run Ruby API application on the nginx web-server. However, it was unsuccessful because browser blocked my fetch() request according to the CORS Policy. I tried to add Access-Control-Allow-Origin: * parameter to the server response header writing it in ruby config file but browser didn't recognize it. Also I tried to set up configuration file on the nginx side but that didn't help me with CORS policy response. That's interesting because using Restlet Application I received response from my own API application with correct information and status "ok".
(async function application() {
let dataRuby = {
url: 'http://IP_address/index',
body: {"name": "21312", "year": "2019"}
};
function getApi(data) {
let myInit = {};
myInit.method = "POST";
myInit.body = JSON.stringify(data.body);
myInit.headers = {
'Content-Type': 'application/json'
};
let myRequest = new Request(data.url, myInit);
return fetch(myRequest).then(
res => res.json()
);
}
let response = await getApi(dataRuby);
console.log(response);
})()
Access to fetch at http://IP_address/index from origin 'null' 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.

Related

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.

REST API call succeeds from curl or python, but fails in browser

I'm trying to build a website that requests JIRA data from a company-owned JIRA Board via REST API and displays the requested data in different graphs. While developing with JavaScript I ran into the CORS header 'Access-Control-Allow-Origin' missing error and therefore could not access the data.
Here is some code:
var url = myUrl;
var auth_string = myJira_user + ":" + myJira_password;
var encoded_string = btoa(auth_string);
var http_headers = {
"Content-Type": "application/json",
Authorization: "Basic " + encoded_string
};
var headers = new Headers(http_headers);
fetch(url, headers)
.then(response => {
return response.json();
})
.then(data => {
console.log(data);
})
.catch(err => {});
This JS script throws the above-mentioned error in my browser console, while a simple python script or curl command with the same parameters works and outputs data. How is that possible?
Modern browsers first check CORS policy on the API server via an HTTP OPTIONS call. This is known as "preflighting a request".
CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
HTTP OPTIONS: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
In effect, the browser first checks with the API server whether it has permission to call and consume APIs from the origin (website where the user is browsing from, identified by domain, protocol, and port). If the API server expects calls to be made from the origin, it returns a success response to the OPTIONS calls and then the browser proceeds to make the GET/POST/etc call. However, if the API server does not recognize the origin from the OPTIONS call, it will return a fail response, and the browser will not proceed with the API call and instead generates the exception you've observerd.
CORS + HTTP OPTIONS is one mechanism in the arsenal of securing API access and mitigating the plethora of security and privacy issues arising from Cross-Site-Scripting.
But to your point, CORS does not impact calls made from non-browser applications. A non-browser application, such as CURL or any code you can write in Python, Node, etc. does not make the OPTIONS calls and therefore, the API server's CORS policies do not apply.
You could setup a middleman/proxy server that receives API requests from your web application, call the target API server, and marshal back the response, therefore circumventing the CORS policy.

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

Requesting API with fetch in javascript has CORS policy error

I'm trying to call some APIs with fetch in my javascript code. I'm developing with ReactJs in my machine and have another development in the same network developing the API with .net in another machine. With postman, I can call the API, but with fetch no. I try to call another API in other server and the result was successful.
I'm using fetch and tried to use axios too. I have found in other question in stack overflow this API: https://gturnquist-quoters.cfapps.io/api/random.
The answer says to try to fetch they and I try but throw same error again.
My code to fetch the gturnquist API:
const myHeader = new Headers();
myHeader.append('Content-Type', 'application/json');
fetch('http://gturnquist-quoters.cfapps.io/api/random', {
method: 'GET', headers: myHeader,
})
.then((res) => {
console.log(res);
return {};
})
.then(res => console.log(res));
and my code to fetch the API that i need:
const myHeader = new Headers();
const token = 'mytoken';
myHeader.append('id-tenant', token);
myHeader.append('Content-Type', 'application/json');
const id = 'myid';
const url = 'myurl';
fetch(`http://10.1.1.35/${url}/${id}`, {
method: 'GET',
headers: myHeader,
}).then(res => res.json()).then(res => console.log(res));
I have this errors when I try to call an API
OPTIONS http://10.1.1.35/url/id 503 (Service Unavailable)
Access to fetch at 'http://10.1.1.35/url/id' from origin 'http://localhost:3000' 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.
Uncaught (in promise) TypeError: Failed to fetch
It's a server side error or javascript error?
In my server, the API is configured like the answer of Rajkumar Peter
EDIT: My network error
Questions i have see to try handle my error:
Fetch CORS error with instagram api
Enable CORS in fetch api
managing CORS with fetch API GET request
React fetch has error fetch was blocked by CORS policy
Response to preflight request doesn't pass access control check
When performing an API call from a web browser, it will often do something called a "preflight check". This is essentially where the browser sends a request to your API (ahead of your own API call), to check what it is allowed to do and whether it's even worth sending the actual request.
To do this, it uses the OPTIONS method (instead of GET, POST .etc).
If your API endpoint hasn't been configured to accept OPTIONS requests, then the preflight request from the browser will fail - and it will abort sending your request.
To fix your issue, you need to configure your API to accept OPTIONS methods. You should also check which origins (IP addresses of clients connecting to the API) are allowed.

Categories

Resources