APIs e Microsserviços

12 mar, 2018

Web flow OAuth GitHub não suporta CORS

Publicidade

Se você está aqui, provavelmente está tendo problemas de CORS ao implementar o web flow Github OAuth.

Perdi a maior parte do meu dia tentando entender o que exatamente eu estava fazendo de errado. Espero que este pequeno artigo ajude.

Estas são as etapas para autenticar com sucesso um usuário no seu aplicativo GitHub:

  1. Os usuários são redirecionados para solicitar sua identidade GitHub
  2. Os usuários são redirecionados de volta ao seu site pelo GitHub
  3. Use o token de acesso para acessar a API

Na etapa 2, o GitHub redireciona o usuário de volta ao seu site enviando code como um parâmetro. Então você precisa enviar o conteúdo do parâmetro code na solicitação POST https://github.com/login/oauth/access_token, para você trocar esse código por um novo access_token.

E é exatamente aí que as coisas ficam instáveis.  Se você tem um aplicativo de navegador puro no JavaScript, ou de alguma forma está executando essa solicitação de um navegador, a resposta será um OPTIONS method error.

Por que isso acontece?

A codificação rígida do seu client_id e client_secret em uma página web ou em algum arquivo .js carregado em seu aplicativo para que todos vejam, não é recomendada. Isso pode causar preocupações de segurança, uma vez que o client_secret deve ser mantido em segredo.

Se alguém tivesse acesso a seu client_id e client_secret, poderia facilmente personificar seu aplicativo, por exemplo, limpando todos os tokens para esse aplicativo usando uma solicitação de Revoke Authorization.

Existe uma issue no GitHub que explica essa preocupação de segurança, veja:

https://github.com/isaacs/github/issues/330.

Solução alternativa (talvez solução definitiva?)

Eu resolvi esse problema criando um arquivo Nodejs de 30 linhas para executar a solicitação POST https://github.com/login/oauth/access_token e me trazer o usuário access_token. Veja:

var axios = require('axios');
var express = require('express');
var app = express();

app.get('/my-oauth', function (req, res) {
  const GITHUB_AUTH_ACCESSTOKEN_URL = 'https://github.com/login/oauth/access_token'
  const CLIENT_ID = '123'
  const CLIENT_SECRET = '456789'
  const CODE = req.query.code

  axios({
    method: 'post',
    url: GITHUB_AUTH_ACCESSTOKEN_URL,
    data: {
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      code: CODE
    }
  })
  .then(function (response) {
  	res.redirect('http://myjsapp/' + response.data)
    console.log('Success ' + response)
  })
  .catch(function (error) {
    console.error('Error ' + error.message)
  })
});

app.listen(3000, function () {
  console.log('my-oauth listening on port 3000!');
});

Eu ainda não sei se eu chamo isso de solução alternativa ou definitiva (não importa). Isso funciona bem porque, obviamente, esse código está sendo executado em um servidor Nodejs leve, e não mais no lado do cliente.

Referências e links úteis

***

Artigo traduzido com autorização do autor. Publicado originalmente em: http://andreybleme.com/2018-02-24/oauth-github-web-flow-cors-problem/