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:
CAMPO | DESCRIÇÃO | OBRIGATÓRIO? |
response_type | Deverá possuir o valor code | Sim |
client_id | Identificador do client obtido junto ao authorization server | Sim |
redirect_uri | URI de retorno cadastrada junto com o client. Deve usar o formato URL Encode. | Não, mas recomendado o uso |
scope | Escopo(s) da solicitação | Não |
state | Valor 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á:
Garantir que a requisição é válida conforme especificado no protocolo OAuth 2.0
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:
CAMPO | DESCRIÇÃO | OBRIGATÓRIO? |
code | Um 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 |
state | Deve 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":
CAMPO | DESCRIÇÃO | OBRIGATÓRIO |
grant_type | Deverá possuir o valor authorization_code | SIM |
code | Obtido no passo anterior | SIM |
redirect_uri | Deverá ser a mesma informada no passo 1 | SIM se tiver sido incluído na requisição de autorização |
client_id | Identificador do client obtido junto ao authorization server | SIM 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á:
Exigir a autenticação do client se o mesmo for do tipo confidential;
Autenticar o client se a autenticação for incluída na requisição;
Garantir que o authorization code foi emitido para o client realizando a requisição de token;
Verificar que o authorization code é válido (existe e não foi utilizado);
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á:
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.
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.