OAuth


No dia 31 de Maio do ano do Senhor de 2010, por volta das 15h, o meu caro amigo Lullis me mandou uma singela mensagem no GTalk dizendo algo como “Você viu que o sistema de Basic Auth do Twitter para de funcionar hoje né? E que daqui pra frente só com OAuth né?”. A frase, descontextualizada, pode parecer apenas mais uma curiosidade geek. O Twitter já vinha anunciando esta migração de modelo de autenticação há um certo tempo.

Mas no mundo de Miguel, isso caiu como uma bomba atômica.

Resumindo: o mecanismo de autenticação usado pelo Job4Dev e pelo SigaSeuTime simplesmente deixaria de funcionar em algumas horas. No caso do SigaSeuTime, isto era uma catástrofe de proporções enormes, já que boa parte do nosso público vem do Twtter. Uma longa noite me aguardava…até que percebemos que Lullis havia falado besteira, e que na verdade o prazo máximo era 31 de junho. Ufa.

Tive então tempo de estudar um pouco o protocolo, e fazer uma implementação usando algumas libs. Por sorte a documentação do próprio Wiki do Twitter é bem interessante. Gostaria de compartilhar alguns pontos aqui.

Basic Auth

É o maior lixo já inventado para autenticação. Basicamente, você adiciona no header da sua requisição um campo cujo valor é o seu username e a sua senha simplesmente codificados em Base 64. Resumindo, senha em claro. Mais básico e inseguro que isso, impossível.

OAuth - Idéia básica

A idéia do OAuth é permitir que o provedor de um serviço permita o acesso a certos recursos a usuários sem precisar dar a senha principal. No caso do Twitter, isto é bem útil, já que a grande maioria dos usuários interagem com o sistema usando aplicativos externos.

Com este protocolo, seria possível permitir que por exemplo o Job4Dev atualizasse a sua timeline, de forma segura e autenticada, sem que eu precisasse guardar a sua senha na minha base de dados. Conveniente!

OAuth - O protocolo

Logo OAuth

Vou tentar tornar esta descrição a mais simples possível.

OAuth usa um mecanismo de pares de chaves públicas e privadas para gerar assinaturas, permitindo uma identificação inequivoca da origem de cada requisição. Simples demais?

Ok

Vamos supor que o usuário @mgalves queria que o Job4Dev publique vagas na sua timeline, usando um app que algum dia será criado. Este app possui duas chaves, geradas pelo @job4dev: um consumer key e um consumer secret (que como seu nome diz, deve ser guardada de forma secreta). O passo a passo seria mais ou menos o seguinte:

  • O app gera uma requisição especial HTTP, usando as duas chaves citadas acima, para obter um token de request temporário.

  • Com este token em mãos, o app gera uma requisição HTTP de autorização de acesso para o Twitter. Esta requisição passa como parâmetros o token, o consumer key e uma assinatura gerada a partir de um hash (SHA) de uma string composta pelo token, pelo consumer key e pelo consumer secret key. Portanto, é única, e apenas o app do Job4Dev é capaz de gerar (comprovando assim a procedência da chamada).

  • O Twitter já sabe, a partir da assinatura, que quem está pedindo permissão de acesso é o Job4Dev. Falta saber qual usuário irá autorizar o acesso: para isso o site pede que eu, @mgalves, efetue o login e explicitamente autorize o acesso.

  • Autorizado o acesso, o Twitter envia para o app um novo par de chaves que serão utilizados para assinar as demais requisições, e que mapeiam de forma única a permissão de acesso do app job4dev aos recursos da conta de @mgalves. Caso eu resolva REVOGAR o acesso, basta invalidar estas novas chaves.

Melhorou? Espero que sim.

Um ponto importante deve ser ressaltado quanto ao último passo. O retorno do novo par de chaves pode ser feito de duas formas: callback e PIN code. Callback é a forma padrão descrita no protocolo do OAuth, e simplemente consiste em definir um callback HTTP no app que está pedindo acesso, que será chamado pelo provedor (no caso o Twitter) ao final do processo passando as chaves por parâmero POST.

Mas isso apenas funciona se o app em questão for web, e puder responder a uma requisição HTTP. Caso isto não aconteça (como no Tweetdeck por exemplo), o Twitter exibe na tela um código numérico único chamado PIN CODE: o app deve receber este PIN code (copy & paste) e gerar uma nova requisição passando o token, o pin code e a assinatura, cujo retorno é o par de chaves.

E o TweetDeck?

Depois de ter lido e entendido o tema, a seguinte dúvida me veio a cabeça: e o TweetDeck, como faz? E nenhum momento eu autorizei o acesso aos meus recursos, e ainda assim, as coisas funcionam. Será que no final de junho ele para de funcionar?

Fucei a documentação do Twitter e achei uma extensão ao protocolo chamada de XAuth, uma pequena variação que permite que as chaves de acesso sejam obtidas através de uma requisição especial contendo username e senha do usuário. Isso evita a necessidade do protocolo definido acima, e funciona bem em casos onde quem vai acessar os recursos é o dono da conta.

Mas segundo o Twitter, para que um app que queira usar este protocolo deve entrar em contato diretamente com eles, explicando a real necessidade.