Gostaria de implementar a autenticação baseada em JWT em nossa nova API REST. Mas como a expiração é definida no token, é possível prolongá-lo automaticamente? Eu não quero que os usuários precisem entrar após cada X minutos se estiverem usando o aplicativo ativamente nesse período. Isso seria uma grande falha no UX.
Mas prolongar a expiração cria um novo token (e o antigo ainda é válido até expirar). E gerar um novo token após cada solicitação parece bobagem para mim. Parece um problema de segurança quando mais de um token é válido ao mesmo tempo. É claro que eu poderia invalidar o antigo usado usando uma lista negra, mas precisaria armazenar os tokens. E um dos benefícios do JWT é o armazenamento.
Eu descobri como o Auth0 resolveu. Eles usam não apenas o token JWT, mas também um token de atualização: https://docs.auth0.com/refresh-token
Mais uma vez, para implementar isso (sem Auth0), eu precisaria armazenar tokens de atualização e manter a validade deles. Qual é o benefício real, então? Por que não ter apenas um token (não JWT) e manter a expiração no servidor?
Existem outras opções? O uso do JWT não é adequado para esse cenário?
Respostas:
Trabalho na Auth0 e estive envolvido no design do recurso de token de atualização.
Tudo depende do tipo de aplicativo e aqui está a nossa abordagem recomendada.
Aplicativos da web
Um bom padrão é atualizar o token antes que ele expire.
Defina a expiração do token como uma semana e atualize o token sempre que o usuário abrir o aplicativo Web e a cada uma hora. Se um usuário não abrir o aplicativo por mais de uma semana, ele precisará fazer login novamente, e esse é o UX do aplicativo Web aceitável.
Para atualizar o token, sua API precisa de um novo terminal que receba um JWT válido, não expirado, e retorne o mesmo JWT assinado com o novo campo de expiração. Em seguida, o aplicativo da Web armazenará o token em algum lugar.
Aplicativos móveis / nativos
A maioria dos aplicativos nativos faz login uma vez e apenas uma vez.
A ideia é que o token de atualização nunca expire e possa ser trocado sempre por um JWT válido.
O problema com um token que nunca expira é que nunca significa nunca. O que você faz se perder o telefone? Portanto, ele precisa ser identificado pelo usuário de alguma forma e o aplicativo precisa fornecer uma maneira de revogar o acesso. Decidimos usar o nome do dispositivo, por exemplo, "iPad da maryo". Em seguida, o usuário pode acessar o aplicativo e revogar o acesso ao "iPad da maryo".
Outra abordagem é revogar o token de atualização em eventos específicos. Um evento interessante está mudando a senha.
Acreditamos que o JWT não é útil para esses casos de uso, portanto, usamos uma sequência gerada aleatoriamente e a armazenamos do nosso lado.
fonte
No caso em que você lida com a autenticação (por exemplo, não use um provedor como Auth0), o seguinte pode funcionar:
O sinalizador 'reauth' no back-end do banco de dados seria definido quando, por exemplo, o usuário redefinisse sua senha. O sinalizador é removido quando o usuário efetuar login na próxima vez.
Além disso, digamos que você tenha uma política na qual um usuário deve fazer login pelo menos uma vez a cada 72 horas. Nesse caso, sua lógica de atualização de token da API também verificaria a data do último login do usuário no banco de dados do usuário e negaria / permitiria a atualização do token nessa base.
fonte
Eu estava mexendo ao mover nossos aplicativos para HTML5 com APIs RESTful no back-end. A solução que surgiu foi:
Como você pode ver, isso reduz as solicitações frequentes de token de atualização. Se o usuário fechar o navegador / aplicativo antes que a chamada de renovação do token seja acionada, o token anterior expirará a tempo e o usuário precisará efetuar novamente o login.
Uma estratégia mais complicada pode ser implementada para atender à inatividade do usuário (por exemplo, negligenciou uma guia do navegador aberta). Nesse caso, a chamada de token de renovação deve incluir o tempo de expiração esperado, que não deve exceder o tempo de sessão definido. O aplicativo precisará acompanhar a última interação do usuário de acordo.
Não gosto da ideia de definir uma expiração longa, portanto, essa abordagem pode não funcionar bem com aplicativos nativos que exigem autenticação menos frequente.
fonte
Uma solução alternativa para invalidar JWTs, sem nenhum armazenamento seguro adicional no back-end, é implementar uma nova
jwt_version
coluna inteira na tabela de usuários. Se o usuário desejar fazer logout ou expirar os tokens existentes, basta aumentar ojwt_version
campo.Ao gerar um novo JWT, codifique-o
jwt_version
na carga útil do JWT, incrementando opcionalmente o valor antecipadamente se o novo JWT deve substituir todos os outros.Ao validar o JWT, o
jwt_version
campo é comparado ao lado deuser_id
e a autorização é concedida somente se corresponder.fonte
Boa pergunta - e há muitas informações na própria pergunta.
O artigo Atualizar tokens: quando usá-los e como eles interagem com os JWTs fornece uma boa ideia para esse cenário. Alguns pontos são: -
Veja também auth0 / angular-jwt angularjs
Para API da Web. leia Habilitar tokens de atualização do OAuth no aplicativo AngularJS usando o ASP .NET Web API 2 e Owin
fonte
Na verdade, eu implementei isso em PHP usando o cliente Guzzle para criar uma biblioteca cliente para a API, mas o conceito deve funcionar para outras plataformas.
Basicamente, emito dois tokens, um curto (5 minutos) e um longo que expira após uma semana. A biblioteca cliente usa o middleware para tentar uma atualização do token curto, se receber uma resposta 401 para alguma solicitação. Ele tentará a solicitação original novamente e, se conseguiu atualizar, obtém a resposta correta, de forma transparente para o usuário. Se falhar, apenas enviará o 401 ao usuário.
Se o token curto expirou, mas ainda é autêntico e o token longo é válido e autêntico, ele atualizará o token curto usando um terminal especial no serviço que o token longo autentica (essa é a única coisa para a qual pode ser usado). Ele usará o token curto para obter um novo token longo, estendendo-o por mais uma semana toda vez que atualizar o token curto.
Essa abordagem também nos permite revogar o acesso em no máximo 5 minutos, o que é aceitável para nosso uso sem precisar armazenar uma lista negra de tokens.
Edição tardia: relendo esses meses depois que estava fresco em minha mente, devo salientar que você pode revogar o acesso ao atualizar o token curto, pois oferece uma oportunidade para chamadas mais caras (por exemplo, ligue para o banco de dados para ver se o usuário foi banido) sem pagar por isso em todas as chamadas para o seu serviço.
fonte
Abaixo estão as etapas para revogar seu token de acesso JWT:
1) Ao fazer login, envie 2 tokens (token de acesso, token de atualização) em resposta ao cliente.
2) O token de acesso terá menos tempo de validade e a atualização terá um longo prazo de validade.
3) O cliente (Front end) armazenará o token de atualização no armazenamento local e o acesso ao token em cookies.
4) O cliente usará o token de acesso para chamar apis. Porém, quando expirar, escolha o token de atualização no armazenamento local e chame a API do servidor de autenticação para obter o novo token.
5) Seu servidor de autenticação terá uma API exposta que aceitará o token de atualização e verificará sua validade e retornará um novo token de acesso.
6) Quando o token de atualização expirar, o usuário será desconectado.
Informe-me se precisar de mais detalhes. Também posso compartilhar o código (inicialização Java + Spring).
fonte
jwt-autorefresh
Se você estiver usando o nó (React / Redux / Universal JS), poderá instalar
npm i -S jwt-autorefresh
.Essa biblioteca agenda a atualização de tokens JWT em um número calculado pelo usuário de segundos antes da expiração do token de acesso (com base na declaração exp codificada no token). Possui um amplo conjunto de testes e verifica algumas condições para garantir que qualquer atividade estranha seja acompanhada por uma mensagem descritiva sobre configurações incorretas do ambiente.
Implementação de exemplo completo
aviso legal: eu sou o mantenedor
fonte
jwt-autorefresh
decodifica é extrair aexp
declaração para que possa determinar até que ponto agendar a próxima atualização.Eu resolvi esse problema adicionando uma variável nos dados do token:
I definir
expiresIn
opção para o meu tempo desejado antes de o usuário será forçado a de login novamente. O meu está definido para 30 minutos. Isso deve ser maior que o valor desoftexp
.Quando meu aplicativo do lado do cliente envia uma solicitação à API do servidor (onde o token é necessário, por exemplo, página de lista de clientes), o servidor verifica se o token enviado ainda é válido ou não com base no valor original de expiração (
expiresIn
). Se não for válido, o servidor responderá com um status específico para esse erro, por exemplo.INVALID_TOKEN
.Se o token ainda é válido com base no
expiredIn
valor, mas já excedeu osoftexp
valor, o servidor responderá com um status separado para esse erro, por exemplo.EXPIRED_TOKEN
:No lado do cliente, se recebeu
EXPIRED_TOKEN
resposta, ele deve renovar o token automaticamente enviando uma solicitação de renovação ao servidor. Isso é transparente para o usuário e cuida automaticamente do aplicativo cliente.O método de renovação no servidor deve verificar se o token ainda é válido:
O servidor se recusará a renovar tokens se falhar no método acima.
fonte
Que tal essa abordagem:
Não exigimos ponto final adicional para atualizar o token neste caso. Gostaria de receber qualquer feedack.
fonte
Hoje, muitas pessoas optam por fazer o gerenciamento de sessões com JWTs sem estar cientes do que estão desistindo em prol da simplicidade percebida . Minha resposta é elaborada na 2ª parte das perguntas:
Os JWTs são capazes de suportar o gerenciamento básico de sessões com algumas limitações. Sendo tokens auto-descritivos, eles não exigem nenhum estado no lado do servidor. Isso os torna atraentes. Por exemplo, se o serviço não tiver uma camada de persistência, ele não precisará trazer uma apenas para o gerenciamento de sessões.
No entanto, apatridia também é a principal causa de suas deficiências. Como eles são emitidos apenas uma vez com conteúdo e expiração fixos, você não pode fazer o que gostaria com uma configuração típica de gerenciamento de sessões.
Ou seja, você não pode invalidá-los sob demanda. Isso significa que você não pode implementar um logoff seguro, pois não há como expirar os tokens já emitidos. Você também não pode implementar o tempo limite ocioso pelo mesmo motivo. Uma solução é manter uma lista negra, mas isso introduz o estado.
Eu escrevi um post explicando essas desvantagens em mais detalhes. Para ficar claro, você pode contornar esses problemas adicionando mais complexidade (sessões deslizantes, tokens de atualização etc.)
Quanto a outras opções, se seus clientes interagirem apenas com o serviço por meio de um navegador, recomendo o uso de uma solução de gerenciamento de sessões baseada em cookies. Também compilei uma lista de métodos de autenticação atualmente amplamente utilizados na web.
fonte