"Vamos usar um token para proteger esta chamada de API. Devo usar o token de ID ou o token de acesso? 🤔 O token de ID parece melhor para mim. Afinal, se eu souber quem é o usuário, posso tomar melhores decisões de autorização, né?"
Você já se pegou debatendo esses pontos? Escolhas feitas pela intuição podem parecer boas, mas o que parece intuitivo nem sempre é o certo. No caso de tokens de ID e de acesso, eles têm finalidades claras e bem definidas, portanto, você deve usá-los com base nisso. Usar o token errado pode resultar em sua solução não-segura.
"O que muda afinal? Eles são apenas tokens. Posso usá-los como bem entender. Qual o pior que pode acontecer?"
Vamos dar uma olhada mais de perto nesses dois tipos de tokens para entender melhor a função deles nos processos de autenticação e autorização.
Se preferir, também pode ver este vídeo sobre o mesmo tópico (em inglês):
O que é um Token de ID?
Um token de ID é um artefato que prova que o usuário foi autenticado. Foi apresentado pelo OpenID Connect (OIDC), um padrão aberto para autenticação usado por muitos provedores de identidade, como Google, Facebook e, claro, Auth0. Confira este documento para saber mais detalhes sobre o OpenID Connect (em inglês). Vamos dar uma olhada rápida no problema que o OIDC quer resolver.
Considere o seguinte diagrama:
Aqui, um usuário com seu navegador se autentica em um provedor OpenID e obtém acesso a uma aplicação web. O resultado desse processo de autenticação baseado no OpenID Connect é o token de ID, que é passado para a aplicação como prova de que o usuário foi autenticado.
Isso dá uma ideia bem básica do que é um token de ID: prova da autenticação do usuário. Vamos ver alguns outros detalhes.
Um token de ID é encodado como um JSON Web Token (JWT), um formato padrão que permite que sua aplicação inspecione facilmente seu conteúdo e verifique se esse conteúdo vem do emissor esperado e que ninguém mais o modificou. Se você quiser saber mais sobre JWTs, confira o Manual do JWT.
Simplificando, um exemplo de token de ID se parece com isso:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vbXktZG9tYWluLmF1dGgwLmNvbSIsInN1YiI6ImF1dGgwfDEyMzQ1NiIsImF1ZCI6IjEyMzRhYmNkZWYiLCJleHAiOjEzMTEyODE5NzAsImlhdCI6MTMxMTI4MDk3MCwibmFtZSI6IkphbmUgRG9lIiwiZ2l2ZW5fbmFtZSI6IkphbmUiLCJmYW1pbHlfbmFtZSI6IkRvZSJ9.bql-jxlG9B_bielkqOnjTY9Di9FillFb6IMQINXoYsw
Claro, isso não é um formato legível para seres humanos, então você precisa decodificá-lo para ver qual conteúdo o JWT contém. Inclusive, o token de ID não é criptografado, mas apenas codificado em Base 64. Você pode usar uma das muitas bibliotecas disponíveis para decodificá-lo ou pode examiná-lo você mesmo com o depurador (ou se preferir em inglês, debugger) jwt.io.
Sem entrar muito nos detalhes, as informações relevantes transportadas pelo token de ID acima se parecem com o seguinte:
{
"iss": "http://my-domain.auth0.com",
"sub": "auth0|123456",
"aud": "1234abcdef",
"exp": 1311281970,
"iat": 1311280970,
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe"
}
Essas propriedades JSON são chamadas de claims (às vezes essas claims também são chamadas de atributos) e são declarações sobre o usuário e o próprio token. As declarações (claims) sobre o usuário definem a identidade do usuário.
Na verdade, as especificações do OpenID Connect não exigem que o token de ID tenha as claims do usuário. Em sua estrutura mínima, o token não possui dados sobre o usuário; apenas informações sobre a operação de autenticação.
Uma claim importante é a aud
. Essa claim define a audiência do token, ou seja, a aplicação Web que deve ser o destinatário final do token. No caso do token de ID, seu valor é o ID do cliente da aplicação que deve consumir o token.
Lembre-se desse pequeno detalhe sobre a claim da audiência, isso ajudará você a entender melhor qual é o seu uso correto mais à frente.
O token de ID pode ter informações adicionais sobre o usuário, como endereço de e-mail, foto, aniversário e assim por diante.
Por fim, talvez o mais importante: o token de ID é assinado pelo emissor com sua chave privada. Isso te garante a origem do token e que ele não foi adulterado. Você pode verificar essas coisas usando a chave pública do emissor.
Legal! Agora você sabe o que é um token de ID. Mas o que você pode fazer com um token de ID?
Primeiro, ele demonstra que o usuário foi autenticado por uma entidade em que você confia (o provedor OpenID) e, então você pode confiar nas claims sobre sua identidade.
Além disso, sua aplicação pode personalizar a experiência do usuário usando as claims sobre o usuário incluídas no token de ID. Por exemplo, você pode mostrar o nome deles na interface do usuário (UI) ou exibir uma mensagem de "feliz aniversário!" no aniversário dele. A parte divertida é que você não precisa fazer requisições adicionais, então você pode ter um pequeno ganho de desempenho para a sua aplicação.
O que é um Token de Acesso?
Agora que você sabe o que é um token de ID, vamos tentar entender o que é um token de acesso.
Vamos começar representando o cenário em que o token de acesso se encaixa:
No diagrama acima, uma aplicação cliente deseja acessar um recurso, por exemplo, uma API ou qualquer outra coisa que esteja protegida contra acesso não autorizado. Os outros dois elementos nesse diagrama são o usuário, que é o dono do recurso, e o servidor de autorização. Nesse cenário, o token de acesso é o artefato que permite que a aplicação cliente acesse o recurso do usuário. Ele é emitido pelo servidor de autorização depois de autenticar o usuário com sucesso e obter o seu consentimento.
No contexto do OAuth 2, o token de acesso permite que uma aplicação cliente acesse um recurso específico para executar ações específicas em nome do usuário. Isso é o que é conhecido como cenário de autorização delegada: o usuário delega uma aplicação cliente para acessar um recurso em seu nome. Isso quer dizer, por exemplo, que você pode autorizar seu aplicativo do LinkedIn a acessar a API do Twitter em seu nome para fazer postagens cruzadas em ambas as redes sociais. Lembre-se de que você autoriza apenas o LinkedIn a publicar suas postagens no Twitter. Você não o autoriza a excluir esses posts, alterar os dados do seu perfil ou fazer outras coisas. Essa limitação é muito importante em um cenário de autorização delegada e é alcançada por meio de escopos. Os escopos são um mecanismo que permite ao usuário autorizar uma aplicação de terceiros a executar apenas operações específicas.
Claro, a API que recebe o token de acesso deve ter certeza de que ele realmente é um token válido emitido pelo servidor de autorização no qual confia e tomar decisões de autorização com base nas informações associadas a ele. Em outras palavras, a API precisa de alguma forma usar esse token para autorizar a aplicação cliente a executar a operação desejada no recurso.
A forma que o token de acesso deve ser usado para tomar decisões de autorização depende de muitos fatores: a arquitetura geral do sistema, o formato do token etc. Por exemplo, um token de acesso pode ser uma chave que permite que a API recupere as informações necessárias de um banco de dados compartilhado com o servidor de autorização, ou pode conter diretamente as informações necessárias em um formato codificado. Isso quer dizer que entender como recuperar as informações necessárias para tomar decisões de autorização é um acordo entre o servidor de autorização e o servidor de recursos, ou seja, a API.
As especificações principais do OAuth 2 não dizem nada sobre o formato do token de acesso. Ele pode ser uma string em qualquer formato. Um formato comum usado para tokens de acesso é o JWT, e uma estrutura padrão está disponível. No entanto, isso não significa que os tokens de acesso devam estar nesse formato.
Ótimo! Agora você sabe o que são um token de ID e um token de acesso. 🎉 Tudo pronto pra você usá-los sem medo de errar. Mas espere. Talvez isso não seja o suficiente para te convencer. 🤔 Provavelmente você precisa de alguma outra informação. OK. Então, vamos ver para que esses tokens não são adequados.
Para que um token de ID NÃO é adequado?
Um dos erros mais comuns que pessoas desenvolvedoras cometem com um token de ID é usá-lo para chamar uma API.
Como dito acima, um token de ID prova que um usuário foi autenticado. Em um cenário primário, ou seja, em um cenário em que o cliente e a API são controlados por você, você pode decidir que seu token de ID é bom para tomar decisões de autorização: talvez tudo o que você precise saber seja a identidade do usuário.
No entanto, mesmo nesse cenário, a segurança da sua aplicação, que consiste no conjunto cliente e API, pode estar em risco. Na verdade, não há mecanismo que vincule o token de ID ao de canal de comunicação entre a API e o cliente. Se um invasor conseguir roubar seu token de ID, ele poderá usá-lo para chamar sua API como um cliente legítimo.
Para o token de acesso, por outro lado, existe um conjunto de técnicas, conhecidas coletivamente como sender constraint (restrição de remetente em tradução livre), que permitem vincular um token de acesso a um remetente específico. Isso garante que, mesmo que um invasor roube um token de acesso, ele não pode usá-lo para acessar sua API, já que o token está vinculado ao cliente que o solicitou originalmente.
Em um cenário de autorização delegada em que um cliente de terceiros deseja chamar sua API, você não deve usar um token de ID para chamar a API. Além da falta de mecanismos para vinculá-lo ao cliente, existem vários outros motivos para não fazer isso.
Se sua API aceitar um token de ID como um token de autorização, para começar, você estará ignorando o destinatário desejado que foi indicado pela claim da audiência. Essa claim diz que ela se destina à sua aplicação cliente, não ao servidor de recursos (ou seja, a API).
Você pode pensar que isso é só uma formalidade, mas há implicações de segurança aqui.
Em primeiro lugar, entre outras validações, sua API não deve aceitar um token que não seja destinado a ela. Se isso acontecer, sua segurança estará em risco. Na verdade, se sua API não se importa se um token é destinado a ela, um token de ID roubado de qualquer aplicação cliente pode ser usado para acessar sua API. É claro que verificar a audiência é apenas uma das verificações que sua API deve fazer para impedir o acesso não autorizado.
Além disso, seu token de ID não terá escopos concedidos (eu sei, esse é outro ponto problemático). Como dito anteriormente, os escopos permitem que o usuário restrinja as operações que sua aplicação cliente pode fazer em seu nome. Esses escopos são associados ao token de acesso para que sua API saiba o que a aplicação cliente pode e o que não pode fazer. Se sua aplicação cliente usa um token de ID para chamar a API, você ignora esse recurso e possivelmente permite que a aplicação execute ações que o usuário não autorizou.
Para que um token de acesso NÃO é adequado?
Do lado do token de acesso, ele foi concebido para demonstrar que você está autorizado a acessar um recurso, por exemplo, para chamar uma API.
Sua aplicação cliente deve usá-lo apenas por esse motivo. Em outras palavras, o token de acesso não deve ser inspecionado pela aplicação cliente. Ele é destinado ao servidor de recursos e sua aplicação cliente deve tratar os tokens de acesso como “strings opacas” (em inglês conhecidas como opaque strings), ou seja, strings sem significado específico. Mesmo que você conheça o formato do token de acesso, não tente interpretar seu conteúdo em sua aplicação cliente. Como dito, o formato do token de acesso é um acordo entre o servidor de autorização e o servidor de recursos, e a aplicação cliente não deve se intrometer. Pense no que pode acontecer se um dia o formato do token de acesso mudar. Se o código do cliente estava inspecionando esse token de acesso, agora ele vai quebrar inesperadamente.
Uma rápida revisão
A confusão sobre o uso de tokens de ID e tokens de acesso é muito comum e pode ser difícil entender as diferenças. Talvez isso aconteça principalmente por não ter uma compreensão clara dos diferentes objetivos de cada artefato, conforme definido pelas especificações OAuth e OpenID Connect. Além disso, entender os cenários em que esses artefatos originalmente deveriam operar tem um papel importante para evitar confusão no seu uso. No entanto, espero que este tópico esteja um pouco mais claro agora.
Para recapitular, aqui está um resumo rápido do que você aprendeu sobre o que você pode e não pode fazer com tokens de ID e de acesso:
Se você quiser ver os tokens de ID e de acesso em ação, inscreva-se para uma conta Auth0 gratuita e comece a adicionar autenticação e autorização em suas aplicações em questão de minutos com sua linguagem de programação e framework preferidos.