Cors error when accessing EBAY User Consent API - javascript

I am attempting to follow this EBAY User Consent API article https://developer.ebay.com/api-docs/static/oauth-consent-request.html
but I am getting a CORS error "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."
I've read numerous Cors posts here this one being a good one: XMLHttpRequest cannot load XXX No 'Access-Control-Allow-Origin' header but none of these solutions seem to work.
a pointer in the right direction would be great.
$(document).on('click','.ebay_access', async function(event) {
let scopes = encodeURIComponent("https://api.ebay.com/oauth/api_scope https://api.ebay.com/oauth/api_scope/sell.marketing.readonly https://api.ebay.com/oauth/api_scope/sell.marketing https://api.ebay.com/oauth/api_scope/sell.inventory.readonly https://api.ebay.com/oauth/api_scope/sell.inventory https://api.ebay.com/oauth/api_scope/sell.account.readonly https://api.ebay.com/oauth/api_scope/sell.account https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly https://api.ebay.com/oauth/api_scope/sell.fulfillment https://api.ebay.com/oauth/api_scope/sell.analytics.readonly https://api.ebay.com/oauth/api_scope/sell.finances https://api.ebay.com/oauth/api_scope/sell.payment.dispute https://api.ebay.com/oauth/api_scope/commerce.identity.readonly https://api.ebay.com/oauth/api_scope/commerce.notification.subscription https://api.ebay.com/oauth/api_scope/commerce.notification.subscription.readonly");
let clientId = "{{env('EBAY_APIKEY')}}";
let clientSecret = "{{env('EBAY_API_CERT_NAME')}}";
let oAuthCredentials64 = btoa(clientId + ":" + clientSecret);
let endpoint = 'https://api.ebay.com/identity/v1/oauth2/token';
try{
let response = await fetch(endpoint,
{
method: "POST",
headers:
{
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": `Basic ${oAuthCredentials64}`
},
body:
"grant_type=client_credentials&scope=" + scopes
}
);
let responseJson = await response.json();
console.log("CLIENT ACCESS TOKEN", responseJson);
} catch(err){
console.log("error: ", err);
};
}); //end function

The request you are making seems to be an authentication request, or "consent request", as eBay call it. This must be made to the authorization endpoint (probably https://api.ebay.com/identity/v1/oauth2/authorize). But you make it to the token endpoint (https://api.ebay.com/identity/v1/oauth2/token), as if it were a token request. But the token request is only the second step ("Exchanging the authorization code for a User access token").
Moreover, neither the authentication request nor the token request are CORS requests:
The authentication request must happen in a visible browsing context, as explained here. The user can only consent if they see what is going on.
The token request is not made by the browser, because this would expose the secret (as pointed out in Jags's answer). It must be made by your server.
In other words: No CORS should be involved at all. The eBay API article explains this correctly.

There are multiple issues here.
In general, if the URL - domain on your browser is not same as the ajax call browser is making then you get this error.
Seems that you have copied the code which was meant for server side execution. You should NEVER expose your credentials to client side. Anyone can use your steal your credentials.
The github link you provided as reference is for server side nodejs application which is running as an app and not under browser.

Related

Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response when using http get req from JS to SlackAPI

I understand that there are many similar questions, but I am posting this because I feel it is slightly different.
I am trying to send a GET request to the Slack API using an HTTP request.
Specifically, the code looks like the following.
import useSWR from "swr";
const useSlackSearch = (query: string) => {
const token = process.env.NEXT_PUBLIC_SLACK_API_USER_TOKEN;
const myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer " + token);
const slackURL = `https://slack.com/api/search.messages?query=${query}`;
const fetcher = async (url: string) => {
const response = await fetch(url, {
headers: myHeaders,
}).then((res) => res.json());
return response;
};
const { data, error } = useSWR(slackURL, fetcher, {
revalidateOnFocus: true,
revalidateOnReconnect: true,
});
if (error) {
return console.log(`Failed to load: ${error}`);
} else if (!data) {
return console.log("Loading...");
} else {
console.log(data);
return data;
}
};
export default useSlackSearch;
The environments I'm using are as follows.
Device: MacBook Air
OS: macOS
Browser: Chrome
From: localhost:3000
To: Slack API html page (https://slack.com/api/search.messages)
After reading the MDN articles like below, I understood that
There is such a thing as a simple HTTP request as defined by MDN
If the request you want to send does not correspond to this simple request, the browser will send a preflight request
In the response to that preflight request, there is a header called Access-Control-Allow-Headers.
Only headers set to the value of this Access-Control-Allow-Headers header can be used as headers in the main request after preflighting.
In this case, I tried to use the Authorization header, but it was trapped by the above restriction.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
That's all I understand.
However, on the official Slack API page for the method in question, it says to specify the token in the Authorization header, so I'm having trouble.
I also don't understand how to specify the Access-Control-Request-Headers in the preflight header, as described in another questioner's thread. The reason is that the only thing that communicates to the Slack API is the browser in this case, and the only relevant source is JavaScript (React / Next.js to be exact)!
After that, I found preflight response from Slack API as follows;
access-control-allow-headers: slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, x-b3-sampled, x-b3-flags
As I thought, I understand that Authorization is not allowed because it is not included as a value. So the question is how to solve it.
Furthermore, I found out later that the preflight request from the browser properly declared that it wanted to use Authorization as an actual request header. However, the preflight response did not contain the value.
Following CBroe's advice, I was able to contact the Slack help center directly, so I asked this problem. What I found out as a result is that HTTP requests from browsers are not supported as of the end of February 2022. Of course, they have received quite a lot of requests regarding this, so they hope to address it at some point.
This time, the browser sent Access-Control-Request-Headers:Authorization in the preflight request. But the Slack API server side did not allow the Authorization header in the request from the browser. Therefore, Authorization was not set in the Access-Control-Allow-Headers in the preflight response from the Slack API side.
As a result, the response from the Slack API side returned Invalid Auth, even though Authorization was added as a header when making an actual request from the browser.
Through this error, I gained a deeper understanding of HTTP requests such as CORS and preflighting, but since it is not explicitly written on the official Slack website, I left it here.
What is Preflight: https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
What is Access-Control-Allow-Header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
What is CORS simple request: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
I could not get the Authorization header to work either. However, Slack provided this example for adding token authentication to the Post body following the deprecation of the query parameters method.
This worked for me to make Web API calls to Slack from the browser (for testing) so that Slack would read the token for authentication. Note, according to Slack's best practices for security, user and bot tokens should be stored with care and not used in client-side Javascript:
try {
const res = await fetch("https://slack.com/api/conversations.list", {
method: "POST",
body: `token=${TOKEN}`, // body data type must match "Content-Type" header
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}).catch((error) => {
console.log(error);
});
if (!res.ok) {
throw new Error(`Server error ${res.status}`);
} else {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.log(error);
}
using token in request body instead of Authorization header worked for me.
axios({
method: 'post',
url: 'https://slack.com/api/chat.postMessage',
data: `text=Hi&channel=D048GGYTJUK&token=${process.env.TOKEN}`
})

Error 400 receieved when fetching from trovo API

I've been granted acces to an API that uses OAuth 2, I've tried it with different API's and my requests were working.
However with the trovo API I seem to get error 400 at every endpoint.
I also get a "blocked by CORS policy: o 'Access-Control-Allow-Origin' header is present on the requested resource."
function fetching() {
fetch("https://open-api.trovo.live/openplatform/validate", {
"method": "GET",
"headers": {
"Accept": "application/json",
"Authorization": "myKey",
"Client-Id": "myID"
}
})
.then(response => {
console.log(response.json());
})
.catch(err => {
console.error(err);
});
}
I also recieved a Client Secret not sure what to do with that.
Here is the documentation from Trovo: https://developer.trovo.live/docs/APIs.html
Altogether I'm quite new to working with API's.
The OAuth flow requires a server, and cannot be done entirely on the front-end. In this example, you would need a server running somewhere other than StreamElements that would keep track of the access and refresh token.
You would then have the front end connect to the server to get the access token instead of directly to Trovo. Reason for this: security. To get the access token you need the private key, and you don't want to be sending that to the front end, or else they can do stuff as if they were you.
Even though stream overlays don't seem like a front end, it's most often just a browser being rendered, as if you just had a website open in chrome.
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
https://www.youtube.com/watch?v=3pZ3Nh8tgTE

How do I resolve a cors error on a fetch or 401?

So I've been experiencing this CORS error and a 401 and have tried chrome plugins to allow for cors with no luck. Here are the errors I'm getting after disabling cors via the plugin:
Access to fetch at 'https://api.playground.klarna.com/payments/v1/sessions' from origin 'https://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Failed to load resource: net::ERR_FAILED
Error: TypeError: Failed to fetch
Before enabling the CORS Chrome Extension I was receiving a Allow-Access-Control-Origin is not set on the first error message. Along with this in the network tab I'm getting a 401 Preflight which indicates unauthorized but I'm setting the Authorization header with the correct credentials so not sure what's happening here. I'm using the codeigniter php framework.
I'm using Basic auth with:
var auth = 'Basic ' + btoa(username:password);
Here's the code:
let postDataSession = {
"purchase_country" : bookingData.purchase_country,
"purchase_currency" : bookingData.purchase_currency,
"locale" : bookingData.locale,
"order_amount" : bookingData.order_amount,
"order_tax_amount" : 0,
"order_lines" : [{
//"type" : "physical",
"reference" : bookingData.order_lines.reference,
"name" : bookingData.item_name,
"quantity" : 1,
"unit_price" : bookingData.order_amount,
"tax_rate" : 0,
"total_amount" : bookingData.order_amount,
"total_discount_amount": 0,
"total_tax_amount" : 0
}]
};
fetch('https://api.playground.klarna.com/payments/v1/sessions', {
method: 'POST',
//mode: 'no-cors',
//Authorization: auth,
headers: {
'Content-Type': 'application/json',
'Authorization': auth,
//'Access-Control-Allow-Credentials' : true,
'Access-Control-Allow-Headers' : 'pm-u, pm-h0, pm-h1, pm-h3, pm-o0, pm-o1, pm-o2, pm-o3, authorization',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Origin': 'https://localhost',
'ACCESS-CONTROL-MAX-AGE' : 3600,
'referrer-policy': 'no-referrer-when-downgrade'
},
body: JSON.stringify(postDataSession),
})
.then(function(response) {
//The following method initializes the Klarna Payments JS library
//window.location.href = baseurl + "customer/klarna_checkout_page";
if (!response.ok) {
return response.text().then(result => Promise.reject(new Error(result)));
console.log(response.status);
}
console.log(response.json(), response);
return response.json();
})
// .then(function(session) {
// window.location.href = baseurl + "customer/klarna_checkout_page";
// })
.then(function(result) {
// If `redirectToCheckout` fails due to a browser or network
// error, you should display the localized error message to your
// customer using `error.message`.
if (result.error) {
alert(result.error.message);
}
console.log(result);
})
.catch(function(error) {
console.error('Error:', error);
});
I've tried it the mode set to no-cors and receive the same response. I've used postman to post the request with the same data and in postman a response is received. Not sure if I'm either missing or overlooking something so a fresh perspective would be helpful. Does anyone have any idea how to proceed with resolving this issue? I want to avoid having to deploy this code to the live domain and be able to test the response on localhost, not sure if that's at all possible with cors.
Browser extensions are notoriously useless at dealing with preflighted requests. It won't help here.
No-cors mode makes the browser silently fail anything that requires CORS permission instead of throwing an exception. It won't help here.
Postman isn't a browser. It's requests aren't triggered by visiting a website. It doesn't implement the Same Origin Policy and doesn't need permission from CORS.
I'm getting a 401 Preflight which indicates unauthorized but I'm setting the Authorization header with the correct credentials so not sure what's happening here.
The browser is making a preflight request asking permission to send a POST request with credentials.
The server is getting the preflight request and complaining that it doesn't have credentials on it.
Either:
Change the server you are making the request to so it grants you permission in your development environment. It needs to allow OPTIONS requests without credentials on them.
Use a proxy that relays your requests to the server
Is your backend .net core web services? If so, I have seen this problem when you call UseCors after UseAuthentication in your pipeline. If you do that, you will need an authenticated token to do the preflight which is why you get a cors error throwing the exception. Move UseCors to before UseAuthentication so that a CORS response does not have to go through the Authentication middleware first.

Azure Ad CORS How call web api url

i want to know how to call another api like custom using js and msal library.
I have project where can call graph api and get data about my profile, by i wondering how to change this to get data from my custom api which is placed (registered) on azure ad.
My tries generates CORS errors.
I can log in to my JS project and i cant call from this project another api except GraphApi ...
For example:
AppFirst (jsproject - localhost:3000) where i log in and get access token --------> (call to my api localhost:44321 ... ) makes error CORS
My code:
function callApi(endpoint, token, callback) {
endpoint = "https://common.onmicrosoft.com/api://myApiClientId";
const headers = new Headers();
const bearer = `Bearer ${token}`;
headers.append("Authorization", bearer);
const options = {
method: "get",
headers: headers
};
fetch(endpoint, options)
.then(response => response.json())
.then(response => callback(response, endpoint))
.catch(error => console.log(error))
}
Can anybody tell me how make this call? Which address is correct to invoke other api?
This is a common CORS issue.
JavaScript can't normally access resources on other origins(This will cause CORS error). "Other origins" means the URL being accessed differs from the location that the JavaScript is running from, by having
a different scheme (HTTP or HTTPS)
a different domain
a different port
Solution:
You need to make changes on the API side.
A Guide to Solving Those Mystifying CORS Issues

Angular 2 access redmine Rest Api, no 'Access-Control-Allow-Origin'

I try to get issues from redmine via them Rest Api. When I call it from Postman I get response, but when I do it from my angular App I get such error
OPTIONS https://redmine.ourDomain.net/issues.json 404 (Not Found)
XMLHttpRequest cannot load https://redmine.ourDomain.net/issues.json. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 404.
Its how I do it in Angular
login(user: User): Observable<boolean> {
var headers: Headers = new Headers();
headers.append("Authorization", "Basic " + btoa(user.login + ":" + user.password));
let options = new RequestOptions({ headers: headers });
return this.http.get("https://redmine.ourDomain.net/issues.json", options)
.map((response: Response) => {
debugger;
if (response.status == 200) {
// set token property
// store username and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify({ user }));
// return true to indicate successful login
return true;
} else {
// return false to indicate failed login
return false;
}
});
}
And there how request looks in my browser
You'll need to enable CORS access on the backend: http://www.redmine.org/plugins/redmine_cors
Here's a nice extension that will let you test frontend code outside of normal CORS restrictions. It's strictly for testing and won't help a production app, but nice to have: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
CORS must be set up in the backend. Please note that is NOT a good practice to allow all origins Access-Control-Allow-Origin: '*' and that you will need to specify the other headers as well:
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: authorization.

Categories