I found a solution, which is in the answers.
I know questions about CORS have been asked many times. In this case I want to understand the justification for the policy, because I don’t at all. I’m also looking for any workaround that isn’t on the server side.
I’m trying to write an extension for Firefox that calls the LeetCode API. For example, this is a fetch request I’m trying to make in JavaScript.
let url = `https://leetcode.com/graphql/?query=query{
allQuestionsCount {
difficulty
count
}
matchedUser(username: "lee215") {
username
}
}`
const response = await fetch(url);
var data = await response.json();
If I simply try to run this code in my browser, I get a CORS error, Reason: CORS header 'Access-Control-Allow-Origin' missing
.
If I temporarily disable CORS with an extension like CORS Everywhere, the code works. My problem is that I don’t want to have to do that. The bigger issue is that CORS Everywhere doesn’t seem to work in the extension environment (only in the plain browser page).
I guess I’m just confused, why can leetcode.com, running in my browser, call the API, while I get an error? Why would this policy stop malicious actors if anyone can read the API response, and the host’s web page can execute JS code with it on my browser? Is there any way for me to get around this?
2
Answers
I was able to solve this problem based on dmfr56's response, but I had to fiddle around with things so I'm going to explain what I did here. A lot of responses to this question are relevant.
I could only get this working in Manifest v2, on Firefox. I didn't try this on Chrome, and none of the simple fixes nor the background script fixes for Manifest v3 worked for me.
Background scripts can get around CORS restrictions (this is basically just another script in your add-on). You have to put a listener in your background script:
background.js:
Then, add the script to your manifest:
Also in your manifest, add permissions for the site you are accessing:
Now, when you want to access the CORS restricted API in your main JavaScript file, use this:
main.js:
The fetch will happen asynchronously and your "received_data" function will have a callback when the data is ready.
It’s important to remember that SOP (Same Origin Policy) affects things on the browser level. My browser, if I open a malicious site, will not allow javascript on the malicious site to access data from another site, in order to block it from stealing data I may have entered on the second site, or performing actions on an account logged in on the second site. The second site can use CORS headers to tell the browser that it’s okay to use the data, but otherwise you’re out of luck.
Extensions are different from websites. Because it is a choice on the user’s part to install them, rather than something that runs as soon as the user loads a page, they are trusted more. An extension can access other websites, but there are some rules you have to follow. The following page has more information about using CORS in an extension:
CORS Chrome Extension with manifest version 2