Mout Pessemier
Mout Pessemier

Reputation: 1995

GitHub API CORS Policy

I'm using jQuery and ajax to do a get request to the GitHub API but after I refresh about 3 times, the request starts to fail saying:

Access to XMLHttpRequest at 'https://api.github.com/users/X/repos' from origin 'my domain' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

even though, I've registered my domain as a GitHub OAuth app.

Here are is my javascript:

let repos = [];
const isEnglish = document.documentElement.lang == 'en';
class Repo {
  constructor(name, description, webUrl, apiUrl) {
    this._name = name;
    this._description = description;
    this._webUrl = webUrl;
    this._apiUrl = apiUrl;
    this._languages = [];
    this.fetchLanguages();
  }

  get name() {
    return this._name;
  }

  get description() {
    return this._description;
  }

  get url() {
    return this._webUrl;
  }

  get languages() {
    return this._languages;
  }

  set languages(value) {
    this._languages = value;
  }

  async fetchLanguages() {
    const url = this._apiUrl + '/languages';
    await $.ajax({
      url: url,
      complete: data => {
        this._languages = Object.keys(data.responseJSON);
      },
    });
  }
}

$(document).ready(async () => {
  $.ajax({
    url: 'https://api.github.com/users/X/repos',
    complete: xhr => {
      repos = xhr.responseJSON.map(json => {
        return new Repo(json.name, json.description, json.html_url, json.url);
      });
      // build up list based on data
      const container = document.getElementById('projectListContainer');
      repos.forEach(repo => {
        const li = document.createElement('li');

        //header
        const collapsibleHeader = document.createElement('div');
        collapsibleHeader.classList.add('collapsible-header');
        const headerText = document.createTextNode(repo.name);
        collapsibleHeader.appendChild(headerText);
        li.appendChild(collapsibleHeader);

        //body
        const collapsibleBody = document.createElement('div');
        collapsibleBody.classList.add('collapsible-body');

        const description = document.createElement('p');
        const descText = document.createTextNode(repo.description);
        description.appendChild(descText);
        collapsibleBody.appendChild(description);

        const languages = document.createElement('p');
        languages.style.marginTop = '1rem';
        const langTxt = isEnglish ? 'Languages used: ' : 'Talen gebruikt: ';
        const langText = document.createTextNode(langTxt + repo.languages);
        languages.appendChild(langText);
        collapsibleBody.appendChild(languages);

        const url = document.createElement('a');
        url.href = repo.url;
        url.target = '_blank';
        url.style.marginTop = '1rem';
        url.style.display = 'block';
        url.style.fontSize = '12px';
        const urlText = document.createTextNode(repo.url);
        url.appendChild(urlText);
        collapsibleBody.appendChild(url);

        li.appendChild(collapsibleBody);
        container.appendChild(li);
      });
    },
    error: () => {
      const container = document.getElementById('projectListContainer');
      const div = document.createElement('div');
      div.classList.add('center');
      const txt = isEnglish
        ? 'Something went wrong or the request limit is reached, check back later!'
        : 'Er is iets fout gegeaan of het maximum aantal requests is bereikt, kom later terug!';
      const text = document.createTextNode(txt);
      div.appendChild(text);
      container.appendChild(div);
    },
  });
  updateTable();
});

const updateTable = () => {
  repos.forEach(repo => {
    const tdLanguages = document.getElementsByClassName(`${repo.name}Lang`)[0];
    tdLanguages.innerHTML = repo.languages.join(', ');
  });
};

Upvotes: 2

Views: 5736

Answers (2)

tomo_iris427
tomo_iris427

Reputation: 158

To tell the truth, GitHub REST API doesn't reject CORS (see old document).
Even if you have the CORS error, it must be another problem.

In my case, it was because of

  • old information: the header requires NOT Authorization: bearer YOUR__TOKEN but Authorization: token YOUR_TOKEN
  • bad usage: only mistype
  • CORS error but success: the console returns the CORS error, but the connection has succeeded.

Upvotes: 1

ABGR
ABGR

Reputation: 5235

For unauthenticated requests, they limit up to 60 requests an hour. You can increase this upto 5000 per hours by authenticating the api requests.

So when I was facing this problem a couple of weeks ago, I created personal_auth_token at gihub and passed this token in the headers and the problem was solved.

To generate personal_auth_token, login to github.com, go to settings -> developers settings -> Personal access tokens and generate one.

Pass this token in headers under Auhtorization: *token*. So in your AJAX request, it could look something like this:

$.ajax({
    url: *yourUrl*
    ...
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', *token*));
    },
});

One thing to note here is DON'T push the code with this token on github if the repository is public. That gets immediately detected and the token is revoked and you're be required to create again one.

For API requests using Basic Authentication or OAuth, you can make up to 5000 requests per hour. Authenticated requests are associated with the authenticated user, regardless of whether Basic Authentication or an OAuth token was used. This means that all OAuth applications authorized by a user share the same quota of 5000 requests per hour when they authenticate with different tokens owned by the same user.

For unauthenticated requests, the rate limit allows for up to 60 requests per hour. Unauthenticated requests are associated with the originating IP address, and not the user making requests.

https://developer.github.com/v3/#rate-limiting

Another solution that effectively worked in my case was solving the CORS issue with a proxy server. In this, you're just required to append the API request URL to a proxy service provider such as, https://cors-anywhere.herokuapp.com/

var url = "http://example.com/repo"; //your api request url,
var proxyUrl = `https://cors-anywhere.herokuapp.com/${url}`;

fetch(proxyUrl)... //Make a request with this proxy url to navigate CORS issue

Upvotes: 2

Related Questions