Skip to content
This page has been auto-translated and may contain errors.View in English

Como os aplicativos lembram de você ​

Você faz login. Você clica em alguma coisa. O servidor não tem a menor ideia de quem você é.

O HTTP é stateless: cada requisição chega do zero, sem memória da anterior e sem nenhum jeito embutido de conectar as duas. O login que deu certo há um segundo não deixou rastro nenhum.

Então um aplicativo que precisa reconhecer você entre requisições precisa guardar a identidade em algum lugar e recuperá-la a cada requisição seguinte.

Toda esta seção gira em torno de uma única pergunta: onde a identidade mora?

Quase todo fluxo de login na web responde isso de uma entre três formas.

O servidor lembra ​

Na identidade stateful, o servidor guarda a informação.

Quando você faz login, o servidor cria uma sessão, um pequeno pacote de dados que representa você: um id de usuário, um nome, talvez um papel. Essa sessão vive no servidor. O navegador recebe um cookie carregando um id de sessão, nada mais, e o envia automaticamente em toda requisição para aquele domínio. O servidor pega o id, busca a sessão correspondente e sabe de novo quem você é.

Esse é o padrão tradicional de aplicativo web, e o comportamento padrão em muitos frameworks. Se você já usou o express-session, era isso que ele estava fazendo.

JunoO servidor lembra O ponto que vale a pena guardar é o quão pouco o navegador recebe de confiança. Ele fica só com um id e nada mais.

Tudo o que importa sobre você fica no servidor, e o id só é útil para quem também consegue acessar esse servidor.

JunoO servidor lembra A busca feita a cada requisição é o detalhe a observar, porque é ao mesmo tempo o ponto forte e o custo desse modelo. Ela significa que o servidor pode alterar ou destruir uma sessão a qualquer momento, e a próxima requisição sente isso imediatamente.

Também significa que toda requisição toca um armazenamento compartilhado. Em um único servidor, isso é memória e sai de graça. Espalhado por vários servidores, é um repositório que todos precisam alcançar, e essa é a primeira peça de infraestrutura que esse modelo exige que você mantenha rodando.

JunoO servidor lembra A revogação instantânea é a propriedade que você está comprando, e ela vale mais do que parece. Demitir alguém, mudar um papel, reagir a um laptop roubado: apague a sessão e a próxima requisição fica anônima. Sem esperar nada expirar.

O que você paga é um problema de coordenação que cresce junto com sua infraestrutura. Sessões na memória do processo morrem junto com o processo e não existem para a instância vizinha, então qualquer escalonamento horizontal exige um repositório compartilhado, e esse repositório se torna algo que precisa ficar no ar para que qualquer pessoa continue logada.

Sessões fixas (sticky sessions) são o atalho tentador, e elas trocam esse problema por um pior: seu balanceamento de carga agora está amarrado à sua autenticação, e perder uma instância desloga todo mundo que ela estava atendendo.

O cliente carrega a prova ​

Na identidade stateless, o servidor não guarda nada sobre você.

O cliente mantém um token e o envia a cada requisição. O servidor verifica o token e responde, sem precisar consultar nada sobre quem você é entre uma requisição e outra.

Isso funciona bem para APIs, aplicativos mobile e sistemas distribuídos, onde memória compartilhada entre servidores é complicada ou inexistente. Se você já chamou uma API e recebeu 401 Unauthorized: missing authorization header, é esse modelo pedindo que você traga sua prova.

Existem duas versões disso, e a diferença importa o suficiente para que cada uma ganhe seu próprio capítulo. Um token opaco (bearer token) é uma string aleatória sem significado que o servidor precisa consultar. Um JSON Web Token carrega a identidade dentro de si mesmo, assinada, de modo que nenhuma consulta é necessária.

JunoO cliente carrega a prova O nome engana um pouco no início. O servidor é stateless em relação a você, não em relação a tudo.

Ele ainda tem um banco de dados cheio de usuários. O que ele deixa de manter é o registro do fato de que você está logado neste exato momento.

JunoO cliente carrega a prova "Bearer" (portador) é a palavra que faz todo o sentido em bearer token, e ela significa exatamente isso: quem o carrega, o possui. O token não está preso a um dispositivo, a um navegador ou a uma rede, então um token copiado é um token funcional.

É por isso que transporte e armazenamento importam tanto aqui. HTTPS em tudo, e um cuidado sério com onde o cliente guarda o token, porque qualquer coisa legível por JavaScript é legível por JavaScript injetado.

JunoO cliente carrega a prova A troca é exatamente o inverso das sessões. Você ganha um servidor que não precisa de estado compartilhado e escala horizontalmente de graça, e abre mão da capacidade de mudar de ideia depois.

Um token que você assinou é válido até expirar, esteja onde estiver, aconteça o que acontecer depois. Não existe uma lista de onde apagá-lo. É por isso que o formato usual em produção é um access token de vida curta somado a um refresh token de vida mais longa que pode ser revogado: isso reintroduz uma consulta, mas só no momento do refresh, não em toda requisição.

E vale dizer isso claramente. A identidade totalmente stateless abre mão da revogação, e qualquer solução que promete os dois ao mesmo tempo colocou algum estado de volta em algum lugar.

Alguém mais garante por você ​

Na identidade delegada, um terceiro em quem você confia confirma quem é o usuário em seu nome.

Seu aplicativo pergunta ao Google se ele reconhece essa pessoa. O Google faz o login e entrega ao seu aplicativo um token comprovando a resposta. Todo botão "Entrar com o Google", "Entrar com o GitHub" e "Entrar com a Apple" é isso.

O atrativo é que você deixa de manter um sistema de senhas. Sem armazenamento de senha, sem fluxo de redefinição, sem vazamento de credenciais que você nunca chegou a guardar. OAuth e identidade delegada explica como essa transferência realmente funciona.

JunoAlguém mais garante por você Pense nisso como ser afiançado por alguém. Você não se prova diretamente para o aplicativo. Alguém em quem o aplicativo já confia confirma você, e o aplicativo aceita a palavra dessa pessoa.

É por isso que você é redirecionado para uma página do Google e depois trazido de volta. A comprovação aconteceu lá.

JunoAlguém mais garante por você Isso elimina uma categoria de risco e adiciona uma dependência. Seu login agora fica fora do ar quando o do provedor fica, e usuários sem conta lá simplesmente não conseguem se cadastrar.

É por isso que a maioria dos aplicativos para consumidor oferece isso junto com email e senha em vez de substituir, e depois precisa lidar com a mesma pessoa chegando pelas duas portas.

JunoAlguém mais garante por você Vale ser preciso aqui, porque o vocabulário costuma sair errado. O OAuth concede autorização delegada: permissão para seu aplicativo agir sobre um recurso. O OpenID Connect é a camada de identidade construída em cima disso, e os botões "entrar com" são OIDC. Usar um access token do OAuth como prova de quem alguém é, em vez de um identity token do OIDC, é um erro real e comum.

O que você herda são as decisões do provedor. O tempo de vida da sessão dele, a recuperação de conta dele, a visão dele sobre o que um endereço de email significa. Se ele deixa alguém recuperar uma conta por número de telefone, isso agora também é a recuperação de conta do seu sistema.

A vinculação de contas é o ponto mais delicado. Casar um login delegado com uma conta existente pelo endereço de email é a primeira coisa que qualquer pessoa tenta, e isso só é seguro quando o provedor verifica o email, o que nem todos fazem.

Lado a lado ​

StatefulStatelessDelegado
Onde a identidade moraNo servidorNo token que o cliente carregaCom o provedor
Custo por requisiçãoUma consultaUma verificação de assinatura, ou uma consultaDepende do token que você acaba usando
Revogar acessoImediatoDifícil, geralmente espera a expiraçãoEm parte, decisão do provedor
Escala horizontalmentePrecisa de um repositório compartilhadoLivrementeLivremente
Principal coisa que você sacrificaCoordenação entre servidoresA capacidade de mudar de ideiaControle e independência

Nenhuma delas é a resposta certa. Elas otimizam para coisas diferentes, e é por isso que sistemas reais costumam usar mais de uma ao mesmo tempo: um login delegado para estabelecer quem você é, uma sessão para o site, tokens para a API.

JunoLado a lado Não tente decorar essa tabela ainda. Ela vai fazer muito mais sentido depois que você vir cada modelo funcionando.

A única frase que vale a pena levar para o próximo capítulo: stateful é para controle, stateless é para escala, delegado é para passar o problema para outra pessoa.

JunoLado a lado Quando você encontrar um sistema desconhecido, o jeito mais rápido de entendê-lo é perguntar onde a identidade é armazenada. Tudo o mais decorre dessa resposta.

Se o servidor guarda, procure como as sessões expiram e onde ficam armazenadas. Se o cliente guarda, olhe o que acontece quando um token vaza e como alguém o revoga. Se um provedor guarda, olhe como as contas são vinculadas.

JunoLado a lado A linha da revogação é a que decide a maioria das discussões reais, e costuma ser descoberta tarde demais. Times escolhem stateless pelas propriedades de escala, colocam em produção, e depois enfrentam o primeiro incidente que exige deslogar imediatamente uma pessoa específica.

O jeito honesto de encarar isso é que você está escolhendo em que vai ser ruim. Stateful é ruim em escala e bom em controle. Stateless é o inverso. Qualquer coisa que promete os dois silenciosamente reintroduziu uma consulta em algum lugar, o que é um design perfeitamente válido, e vale reconhecer isso pelo que é em vez de tratar como se fosse ganho de graça.

Experimente ​

Para cada sistema, indique o modelo que você esperaria e a propriedade que decide isso.

  1. Um painel administrativo interno onde revogar o acesso de alguém precisa surtir efeito imediatamente.
  2. Uma API pública atendendo um aplicativo mobile com algumas centenas de milhares de usuários.
  3. Um aplicativo de fotos cujo cadastro inteiro é um botão "Continuar com o Google".
  4. Uma arquitetura de microsserviços onde uma dezena de serviços precisa saber quem está chamando.
Compare suas respostas
#ModeloA propriedade decisiva
1StatefulRevogação imediata. Apague a sessão e a próxima requisição fica anônima. Nada mais oferece isso.
2StatelessNão há repositório de sessão compartilhado para coordenar conforme o tráfego cresce, e os clientes mobile carregam um token sem problema.
3DelegadoNenhum sistema de senhas para construir, armazenar ou ter vazado, e o cadastro mais rápido possível.
4Stateless, especificamente JWTsCada serviço consegue verificar o token sozinho, sem precisar perguntar a um servidor central a cada chamada.

O número 1 é o mais interessante. É o menor sistema da lista e o que tem menos pressão de escala, e mesmo assim leva o modelo que escala pior, porque aqui controle importa mais do que crescimento.

Para onde isso vai a seguir ​

Três famílias, cada uma resolvendo um problema de um jeito diferente.

Sessões e cookies desmonta a primeira: o que o servidor armazena, o que o navegador carrega, e os erros que transformam um modelo sólido em um modelo furado.