OAuth 2.0: Authorization Code Flow

Esmiuçando o fluxo de autorização mais utilizado do protocolo

Se você caiu de paraquedas nesse artigo e não conhece nada sobre OAuth 2.0 recomendo iniciar pelo artigo OAuth 2.0: Introdução que, como o nome diz, faz uma leve introdução ao protocolo OAuth 2.0, apresentando de forma sucinta sua origem, problemas que busca resolver e os papéis definidos.

Um pouco de teoria

O Authorization code grant trata-se de um fluxo baseado em redirect onde "o client deve ser capaz de interagir com o resource owner`s user-agent (geralmente um navegador web / browser) e capaz de receber requisições (via redirecionamentos) do authorization server".

No dia-a-dia isso se traduz em aplicações frontend executando no dispositivo do usuário final (normalmente em um browser) e que são capaz de seguir redirects do protocolo HTTP, sendo o usuário final o resource owner (conforme explica no artigo introdutório).

Detalhando o fluxo

Sem mais delongas vamos ao detalhamento do fluxo.

A figura abaixo detalha todo o fluxo desde a requisição de autorização, passando pela autenticação do usuário, posterior obtenção do access token e finalmente a requisição realizada pelo client ao resource server para acesso a algum recurso protegido. O authorization code flow corresponde aos passos 1 a 5 da figura abaixo. Os passos 6, 7 e 8 dizem respeito ao uso do token obtido e é igual para outros authorization flows do OAuth 2.0.

O fluxo inicia com o usuário acessando a aplicação cliente (passo 1) que por sua vez verifica através de seus próprios meios (a especificação não detalha isso) se já possui ou não a autorização necessária.

Uma vez que a aplicação cliente ainda não possui a autorização necessária ela irá direcionar o usuário, através do browser, para o authorization server (passo 2). Para isso ela precisar criar a URI conforme determina a especificação e realizar um HTTP Redirect para a URI criada. Essa etapa é denominada authorization request.

A URI criada deve ser composta por:

CAMPODESCRIÇÃOOBRIGATÓRIO?
response_typeDeverá possuir o valor codeSim
client_idIdentificador do client obtido junto ao authorization serverSim
redirect_uriURI de retorno cadastrada junto com o client. Deve usar o formato URL Encode.Não, mas recomendado o uso
scopeEscopo(s) da solicitaçãoNão
stateValor opaco aleatório que deve ser utilizado pelo client para manter estado entre as requisições e seus retornos.Não, mas recomendado o uso

Abaixo um exemplo de URI a ser formada:

https://authorization-server:8080/auth?
response_type=code
&client_id=my-client
&redirect_uri=http%3A%2F%2Flocalhost%3A8080
&scope=profile+email
&state=HlWY1ubcebm2lmuHWk98fYnEy1f7i6hszdNPCXOw
  • URI está "quebrada" em várias linhas para facilitar a leitura

  • O authorization endpoint deve ser obtido junto ao authorization server

Como resultado dessa ação o usuário, através de seu browser, será direcionado para o Authorization Server que deverá:

  1. Garantir que a requisição é válida conforme especificado no protocolo OAuth 2.0

  2. Realizar a autenticação do usuário e obter sua autorização (como isso será realizada foge do escopo da especificação)

Observe que o passo 2 acima corresponde ao passo 2.1 da nossa figura onde o usuário apresenta ao Authorization Server suas credenciais (usuário e senha, otp ou qualquer outra credencial que o authorization server requisitar).

Se o processo acima for realizado com sucesso o Authorization Server deverá utilizar a redirect uri recebida na authorization request (neste caso localhost:8080) para redirecionar o usuário novamente para a aplicação cliente (passo 3, denominado authorization response).

Nesse redirect o Authorization Server deve incluir como query params:

CAMPODESCRIÇÃOOBRIGATÓRIO?
codeUm código de autorização gerado pelo Authorization Server. Deve expirar em um curto espaço de tempo a fim de minimizar risco de vazamento. A especificação recomenda um tempo máximo de expiração de 10 minutos. O authorization code não pode ser re-utilizado.SIM
stateDeve possuir o mesmo valor do state recebido na requisição de autorização (passo 2)SIM se tiver sido recebido na requisição de autorização

Abaixo um exemplo de URI a ser formada pelo Authorization Server para redirect do usuário final (resource owner) de volta para a aplicação cliente:

http://localhost:8080
&code=4cec7988-0abe-4af0-a663-cfc1e8ac969e.24ba142e-3400-42b4-acc0-e30bf5369dad.a101cd99-ed1e-4988-bb3a-132cccf292db
?state=HlWY1ubcebm2lmuHWk98fYnEy1f7i6hszdNPCXOw

A aplicação cliente irá então extrair o code obtido do Authorization Server para então realizar a requisição denominada Access Token Request (passo 4) que deverá ser uma requisição HTTP POST com os seguintes parâmetros enviados no body da requisição no formato "application/x-www-form-urlencoded":

CAMPODESCRIÇÃOOBRIGATÓRIO
grant_typeDeverá possuir o valor authorization_codeSIM
codeObtido no passo anteriorSIM
redirect_uriDeverá ser a mesma informada no passo 1SIM se tiver sido incluído na requisição de autorização
client_idIdentificador do client obtido junto ao authorization serverSIM se não for necessário autenticação para o client (public client). Se a autenticação for necessário, usar HTTP BASIC Authentication

Sobre autenticação do client: a especificação define dois tipos de clients, sendo public clients e confidential clients. A diferença entre eles é que public clients não possuem credenciais para se autenticar junto ao Authorization Server e confidential clients possuem. Entender as diferenças entre os tipos de clients é trabalho para um próximo artigo.

Abaixo exemplo de requisição a ser realizada:

POST /token HTTP/1.1
Host: authorization-server:8080
Authorization: Basic Y2xpZW50LWlkOmNsaWVudC1zZWNyZXQ=
Content-type: application/x-www-form-urlencoded

grant_type=authorization_code
&redirect_uri=http%3A%2F%2Flocalhost%3A8080
&client_id=my-client
&code=4cec7988-0abe-4af0-a663-cfc1e8ac969e.24ba142e-3400-42b4-acc0-e30bf5369dad.a101cd99-ed1e-4988-bb3a-132cccf292db

Ao receber a requisição o Authorization Server deverá:

  1. Exigir a autenticação do client se o mesmo for do tipo confidential;

  2. Autenticar o client se a autenticação for incluída na requisição;

  3. Garantir que o authorization code foi emitido para o client realizando a requisição de token;

  4. Verificar que o authorization code é válido (existe e não foi utilizado);

  5. Garantir que a redirect_uri recebida é a mesma da constante na authorization request (passo 2)

Se tudo estiver OK o Authorization Server irá emitir resposta (passo 5) contendo:

  • access_token: corresponde ao token para realização de requisição ao resource server;

  • token_type: indica do tipo de token emitido, comumente Bearer;

  • expires_in: tempo de expiração do token, em segundos;

  • refresh_token: um token utilizado para a obtenção de novos access_token sem que todo o processo tenha que ser realizado novamente;

Abaixo exemplo de resposta do Authorization Server:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8

{
  "access_token":"2YotnFZFEjr1zCsicMWpAA",
  "token_type":"example",
  "expires_in":3600,
  "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
}

Com o token "em mãos" a aplicação cliente poderá realizar requisições (passo 6) ao authorization server que por sua vez deverá:

  1. Validar o access_token recebido, sendo uma das formas possíveis através da requisição de token introspection (passo 7), assunto para outro artigo.

  2. Emitir ou não resposta (passo 8) para a aplicação cliente (mesmo o access token sendo válido o resource server pode negar a requisição em função de seus próprios controles).

Conclusão

Há muito a se explorar a respeito do fluxos de autorização estabelecidos pelo OAuth 2.0. Hoje alguns novos termos foram apresentados, como authorization endpoint, token endpoint, confidential e public clients, refresh token, token introspection requests e outros. Seria cansativo e audacioso tentar abordar tudo em um único artigo. Aos poucos vamos, artigo a artigo, explorando esses temas.

Te vejo lá :)

#disclaimer

Dicas, sugestões, correções e críticas construtivas são bem-vindas.