詳細検索

Desmistificado de OAuth: Um Tutorial Direto de OAuth

Avatar
por Chen Ziyu

Desmistificado de OAuth: Um Tutorial Direto de OAuth
Traduzido do English • Ver original

Incorporar OAuth (abreviação de Open Authorization) em uma aplicação pode parecer um tanto intimidador e desanimador para muitos engenheiros de software iniciantes. Afinal, eles precisam passar horas — ou até dias — implementando um processo de autenticação complicado com a configuração correta, apenas para perceber que só completaram uma pequena funcionalidade. Apesar de todo o trabalho árduo que isso implica, OAuth é uma forma segura e eficiente para usuários concederem acesso a sites e aplicativos às suas informações pessoais. Portanto, vale a pena o esforço para entender como OAuth funciona. Neste artigo, vou detalhar todas as etapas envolvidas no processo OAuth para ajudar você a dar início à sua jornada OAuth.

Duas coisas a notar antes de começarmos o tutorial:

  1. A versão OAuth que usarei neste artigo é OAuth 2.0, pois é o padrão atual da indústria. 'https' (TLS) é necessário para ser seguro.
  2. Embora o PKCE seja opcional, decidi incluí-lo neste tutorial porque torna todo o processo OAuth mais seguro.

Vamos supor que temos duas aplicações: o Aplicativo A (aplicativo cliente) e o Aplicativo B (servidor de autorização). O Aplicativo A quer acessar as informações do Usuário X armazenadas no Aplicativo B. Precisamos estabelecer um processo OAuth para que o Aplicativo A possa acessar com segurança essas informações potencialmente sensíveis.

Passo 1: Geração de URL de Autorização

Para permitir que o Aplicativo A acesse as informações do Usuário X no Aplicativo B, o Aplicativo B precisa verificar primeiro a identidade do Usuário X. A maneira mais direta do Aplicativo B verificar a identidade do Usuário X é pedir ao Usuário X que faça login no Aplicativo B. No entanto, o Usuário X NÃO deve fazer login diretamente no Aplicativo B sem envolver o Aplicativo A. A URL de login precisa incluir informações do Aplicativo A para que o Aplicativo B esteja ciente do destino, ou seja, do Aplicativo A, para o qual deve enviar as informações do Usuário X. É aí que entra em cena a URL de autorização. Uma URL de Autorização é essencialmente uma URL para informar o Aplicativo B sobre a tentativa do Aplicativo A de acessar as informações do Usuário X. O Aplicativo B redireciona o Usuário X para sua página de login depois. Para criá-lo, você precisa das seguintes informações:

  1. ID do Cliente
  2. Verificador de Código
  3. Desafio de Código
  4. Método de Desafio de Código
  5. Redirecionar URI

O ID do Cliente é um identificador público do Aplicativo A emitido pelo Aplicativo B. Ele ajuda o Aplicativo B a confirmar a identidade do Aplicativo A. Sem o ID do Cliente, o Aplicativo B se recusaria a fornecer informações sensíveis ao Aplicativo A por falta de confiança.

Tanto o Code Verifier quanto o Code Challenge fazem parte do processo PKCE (abreviação de Proof Key for Code Exchange) que visa tornar as concessões de Código de Autorização mais seguras. Verificador de Código é um código aleatório que atende a alguns requisitos, enquanto Code Challenge é uma transformação do Verificador de Código. No Passo 1, só precisamos do Desafio de Código. Não utilizaremos o Verificador de Código até a Etapa 2.

Você pode usar o código a seguir para criar Verificadores de Código e Desafios de Código.

Importação
Importação de SO
Importado base64
importação de hashlib

code_verifier = base64.urlsafe_b64encode(os.urandom(50)).decode("utf-8")
code_verifier = re.sub("[^a-zA-Z0-9]+", "", code_verifier)
code_challenge = hashlib.sha256(code_verifier.encode("utf-8")).digest()
code_challenge = base64.urlsafe_b64encode(code_challenge).decode("utf-8")
code_challenge = code_challenge.replace("=", "")

O Método de Desafio de Código é o método de codificação usado para transformar o Verificador de Código em Desafio de Código. Normalmente, o OAuth 2.0 usa SHA-256 como método de desafio de código, assim como no exemplo acima.

O URI de redirecionamento é uma API de callback no Aplicativo B que o Aplicativo A é acionada após o login do Usuário X. Explicarei seu propósito com mais detalhes depois.

Depois de reunir todas as informações acima, você pode começar a montar a URL de autorização. Em Python, podemos usar uma biblioteca chamada requests_oauthlib para isso.

de requests_oauthlib importar OAuth2Session

app_b = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI)
authorization_url, _ = app_b.authorization_url(AUTH_URL, code_challenge=code_challenge, code_challenge_method="S256")

No exemplo de código acima, o Aplicativo A usa o construtor 'OAuth2Session' para inicializar a instância 'app_b' com o ID do Cliente e o URI de Redirecionamento como parâmetros. Em seguida, o Aplicativo A cria uma URL de Autorização usando o método 'authorization_url'. Os parâmetros incluem a URL base da API de autorização do Aplicativo B, o Desafio de Código e o Método de Desafio de Código. A URL de Autorização gerada no exemplo de código acima é a seguinte:

https://www.example.com/get\_authorization\_token?response\_type=code&client\_id=&code\_challenge=&code\_challenge\_method=S256

Assim que a URL de Autorização estiver pronta, o Aplicativo A pode enviá-la ao Usuário X e pedir que ele a abra. Após o Usuário X abrir a URL de Autorização, o Aplicativo B registra o pedido do Aplicativo A para acessar as informações do Usuário X e redireciona o Usuário X para a página de login do Aplicativo B.

Passo 2: Buscar Tokens e Recuperar Informações na API de Callback

O Usuário X fez login no Aplicativo B. E agora? O Aplicativo B então envia uma resposta de redirecionamento para o Usuário X para redirecionar o Usuário X para a API de Retorno de Chamada do Aplicativo A especificada no URI de Redirecionamento. Os propósitos da API de Retorno de Chamada são duplos: buscar tokens e recuperar as informações do Usuário X do Aplicativo B.

Primeiro, vamos começar pelos dois tokens que o App A precisa buscar do App B: Access Token e Refresh Token. O Access Token é necessário para obter acesso a recursos protegidos. No nosso caso, o App A não pode acessar as informações do Usuário X no App B até que possua um Access Token emitido pelo App B. O Access Token é irrevogável, o que significa que o App B não pode revogá-lo após enviá-lo para o App A. Portanto, os Access Tokens são poderosos e perigosos pelo mesmo token (sem trocadilhos). Para evitar possíveis vazamentos de dados, os Access Tokens geralmente têm vidas curtas.

Tornar os Access Tokens de curta duração desempenha um papel significativo na garantia da segurança dos dados. No entanto, isso cria um problema diferente em termos de experiência do usuário: os usuários precisam se reautenticar frequentemente para obter novos Access Tokens, pois os Access Tokens expiram com frequência. Felizmente, temos o Refresh Token para nos ajudar. O Refresh Token serve para obter novos Access Tokens quando os Access Tokens atuais expiram. No nosso exemplo, o App B envia um Refresh Token junto com o Access Token inicial para o App A. Em vez de pedir ao Usuário X para entrar novamente no App B após o expirar do Access Token atual, o App A pode usar o Refresh Token para obter um novo Access Token do App B.

Para obter o Access Token e o Refresh Token iniciais, precisamos das seguintes informações:

  1. URL do token
  2. Código de Autorização
  3. Verificador de Código
  4. Método de Desafio de Código
  5. ID do Cliente

URL do Token: A URL do Token é a API para emissão e renovação de tokens do lado do App B.

Código de Autorização: Código de Autorização é um código fornecido pelo Aplicativo B. O Aplicativo B o anexa ao final da API de Retorno do Aplicativo A como um parâmetro de URL.

Verificador de Código: Por favor, consulte minha explicação anterior sobre o Verificador de Código.

Desafio de Código: Por favor, consulte minha explicação anterior sobre o Método de Desafio de Código.

ID do Cliente: Por favor, consulte minha explicação anterior sobre o ID do Cliente.

O exemplo de código a seguir faz uma chamada de API para o Aplicativo B para obter o Access Token inicial, o Refresh Token e informações sobre quando o Access Token expirará.

# de requests_oauthlib importar OAuth2Session
# app_b = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI)

token = app_b.fetch_token( 
    token_url=TOKEN_URL, 
    code=auth_code, 
    code_verifier=code_verifier, 
    code_challenge_method='S256', 
    client_id=CLIENT_ID, 
)
access_token = ficha["access_token"]
refresh_token = token["refresh_token"]
expires_at = ficha["expires_at"]
expires_in = token["expires_in"]

Token de Acesso: Para atualizar o Token de Acesso usando o Token de Atualização, precisamos das seguintes informações:

  1. URL do token
  2. Token de Atualização
  3. ID do Cliente
  4. Segredo do Cliente

URL do Token: Por favor, consulte minha explicação anterior sobre a URL do Token.

Token de Atualização: Por favor, consulte minha explicação anterior sobre o Token de Atualização.

ID do Cliente: Por favor, consulte minha explicação anterior sobre o ID do Cliente.

Cliente Secret é uma credencial conhecida apenas pelo aplicativo OAuth e pelo servidor de autorização. No nosso caso, Cliente Secret atua como uma senha para ajudar o Aplicativo B a verificar a identidade do Aplicativo A.

O exemplo de código a seguir faz uma chamada de API para o Aplicativo B para atualizar o Access Token.

# de requests_oauthlib importar OAuth2Session
# app_b = OAuth2Session(CLIENT_ID, redirect_uri=REDIRECT_URI)

token = app_b.refresh_token( 
    token_url=TOKEN_URL, 
    refresh_token=refresh_token, 
    client_id=CLIENT_ID, 
    client_secret=CLIENT_SECRET
)
access_token = ficha["access_token"]
expires_at = ficha["expires_at"]
expires_in = token["expires_in"]

Munido do Código de Acesso, o Aplicativo A finalmente pode recuperar as informações do Usuário X do Aplicativo B em nome do Usuário X. Tudo o que o Aplicativo A precisa fazer é fazer uma chamada de API para a API designada do Aplicativo B para oferecer informações do usuário a aplicativos externos (normalmente terminando com "/me"), com o Token de Acesso como parte dos cabeçalhos da solicitação.

resposta = solicitações.solicitação( 
    "VÁ", 
    ME_URL, 
    headers={"Authorization": "Bearer {}".format(token["access_token"])}, 
)

Passo 3: O que vem a seguir?

Dependendo das especificações do Aplicativo A, o Aplicativo A pode fazer o seguinte na API de Retorno de Chamada:

  1. O Aplicativo A pode armazenar as informações do Usuário X em seu banco de dados.
  2. O App A pode armazenar o Access Token e o Refresh Token na sessão para acompanhar o status de autenticação do Usuário X no App B. Quando o Token de Atualização expirar, o App A pode considerar a sessão do Usuário X expirada e deslogar o Usuário X.

Avisos legais

Antes de encerrar este artigo, gostaria de observar que diferentes servidores de autorização (App B) podem ter implementações ligeiramente diferentes. Portanto, recomendo gentilmente que você encare os exemplos de código deste artigo com cautela, especialmente ao determinar quais parâmetros incluir nas chamadas de API para servidores de autorização. Ao implementar seu aplicativo cliente (App A) e projetar como ele deve interagir com seu servidor de autorização de destino (App B), consulte a documentação ou o código do servidor de autorização para entender quais variáveis são necessárias para quais chamadas de API.

Neste artigo, demonstrei como configurar um processo OAuth em uma aplicação cliente para acessar recursos protegidos em outra aplicação. Também expliquei quais variáveis precisamos para cada etapa do processo OAuth e por que precisamos delas. Espero que este artigo tenha ajudado você a entender um pouco melhor o OAuth.

Related Articles