16

import request from 'superagent';

const self = this;
    request
      .post('https://github.com/login/oauth/access_token')
      .set('Content-Type', 'multipart/form-data')
      .query({
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
        callback: 'http://127.0.0.1:3000/callback',
        code,
        state,
      })
      .end((err, res) => {
        const token = res.body.access_token;
        console.log(token);
        self.setToken(token);
      });

The code above will give me an error like this

XMLHttpRequest cannot load https://github.com/login/oauth/access_token?client_id=112asdecf3805fdada12&…127.0.0.1%3A3000%2Fcallback&code=434ebd7bb98d9809bf6e&state=HelloWorld1234. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3000' is therefore not allowed access.

I have no idea why even though I've registered the oauth application with github and callback url is http://127.0.0.1:3000/callback

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197

1 Answers1

14

While all the actual GitHub API endpoints support CORS by sending the right response headers, it is a known issue that the https://github.com/login/oauth/access_token endpoint for creating an OAuth access token does not support CORS requests from Web applications.

The very specific workaround for this case is to use https://github.com/prose/gatekeeper:

Gatekeeper: Enables client-side applications to dance OAuth with GitHub.

Because of some security-related limitations, Github prevents you from implementing the OAuth Web Application Flow on a client-side only application.

This is a real bummer. So we built Gatekeeper, which is the missing piece you need in order to make it work.

The general workaround is: Use an open reverse proxy like https://cors-anywhere.herokuapp.com/

var req = new XMLHttpRequest();
req.open('POST',
  'https://cors-anywhere.herokuapp.com/https://github.com/login/oauth/access_token',
  true);
req.setRequestHeader('Accept', 'application/json');
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send('code=' + encodeURIComponent(location.query.code) +
    '&client_id=foo' +
    '&client_secret=bar');
...

See also How to use Cors anywhere to reverse proxy and add CORS headers.

Community
  • 1
  • 1
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • 2
    How concerned should users be with providing their client id and secret to an untrusted open reverse proxy? – osowskit Feb 11 '17 at 02:05
  • @osowskit Clearly they should be concerned. Use at your own risk and all that. If the owner of the proxy wants to log credentials from the requests they can. Which is why it’d of course be better to run Gatekeeper or other such a proxy on their own site instead. (And why I said an open reverse proxy is a more a “general solution” for the case of working around CORS restrictions for sites that don’t opt in receiving cross-origin XHR/Fetch requests.) – sideshowbarker Feb 11 '17 at 02:18
  • 1
    Or use something like AWS API Gateway to create your own authorisation call and keep your client_secret secret – TimoSolo May 12 '17 at 12:27