spinny:~/writing $ less passkeys-webauthn-passwordless-authentication.md
12As senhas são uma daquelas coisas que normalizamos só porque convivemos com elas há anos. Os usuários os esquecem, os reutilizam, os escrevem onde não deveriam. As equipes devem gerenciar redefinições, políticas, hashes, vazamentos, phishing e suporte.34O passkey não torna a autenticação perfeita, mas elimina um grande problema: o servidor não precisa mais manter um segredo compartilhado com o usuário.56## O que realmente acontece78Um passkey é uma credencial baseada em WebAuthn. Quando o usuário o cria, o dispositivo gera um par de chaves:910- uma chave privada, que permanece no dispositivo ou no gerenciador de senhas;11- uma chave pública, que o servidor pode salvar.1213Ao fazer login o servidor não pergunta "diga-me a senha". Envie um desafio aleatório. O dispositivo assina com a chave privada. O servidor verifica a assinatura com a chave pública.1415Essa é a parte legal: se o banco de dados for roubado, não haverá senhas dentro dele para serem quebradas. E se um usuário acabar em um domínio falso, o passkey não é válido para esse domínio. Não é apenas conveniência, é uma proteção concreta contra phishing.1617## O navegador funciona como uma ponte1819No navegador, os dois API principais são:2021- `navigator.credentials.create()` para criar um passkey;22- `navigator.credentials.get()` para usá-lo durante o login.2324Mas a lógica importante está no servidor. O servidor deve gerar o desafio, salvá-lo temporariamente, verificar a resposta, verificar a fonte e Relying Party ID e então criar a sessão.2526A parte do cliente deve ser quase chata:2728```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());3031const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});3435await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```4142Se você estiver implementando a criptografia WebAuthn manualmente, pare. Use uma biblioteca robusta do lado do servidor. Os erros aqui não são "bugs fofos", são falhas de autenticação.4344## O que salvar no banco de dados4546Não há necessidade de salvar metade do mundo. Geralmente é suficiente:4748- ID da credencial;49- chave pública;50- usuário conectado;51- qualquer contador de verificação ou metadados;52- transportes, se forem úteis para UX;53- nome escolhido pelo usuário;54- data de criação e última utilização.5556Uma tabela mínima pode ser assim:5758```sql59create table passkey_credentials (60 id uuid primary key default gen_random_uuid(),61 user_id uuid not null references users(id),62 credential_id text not null unique,63 public_key text not null,64 name text,65 created_at timestamptz not null default now(),66 last_used_at timestamptz67);68```6970Então eu adicionaria registros de auditoria e notificações: se alguém criar um novo passkey na minha conta, quero saber sobre isso.7172## UX é mais importante do que demonstração7374A demonstração de um passkey é sempre linda: você clica, Face ID, você entra. O produto real é mais complicado.7576Alguém muda de telefone. Alguém usa um computador da empresa bloqueado. Algumas pessoas não entendem porque o navegador sugere passkey. Alguém perde o acesso ao seu dispositivo.7778É por isso que eu não começaria com “a partir de hoje não há mais senhas para todos”. Eu começaria assim:79801. passkey opcional para usuários internos;812. sugestão de criação de um após login bem-sucedido;823. página da conta para renomear e remover passkey;834. alternativa clara;845. implementação gradual no login principal.8586O texto na interface deve ser simples. "Usar a tela de bloqueio do seu dispositivo" é melhor do que "autenticar com uma credencial de residente FIDO2".8788## Erros que eu evitaria8990Não gere desafios ao cliente. O desafio é criado no servidor e deve ser verificado apenas uma vez.9192Não confie apenas no ID da credencial. Você precisa verificar assinatura, desafio, origem e Relying Party ID.9394Não exclua substitutos antes de ter um bom fluxo de recuperação. Sem senha não precisa se tornar “se você perder seu telefone, estará fora para sempre”.9596Não trate o passkey como um botão puramente frontend. Ocultar um botão não é segurança: a verdadeira verificação é do lado do servidor.9798## Passkey-primeiro ou passkey-amigável?99100Para um novo produto, você pode pensar primeiro em passkey. Para um aplicativo existente, prefiro passkey amigável: adicione passkey como método recomendado, meça o sucesso e os problemas e, em seguida, reduza com calma o peso da senha.101102A migração ideal não se faz sentir. O usuário descobre que o login é mais fácil, e não que a empresa tenha alterado seu protocolo de autenticação.103104## Conclusão105106Os passkey são interessantes porque melhoram a segurança e a UX ao mesmo tempo, o que é raro. Eles não são uma varinha mágica: recuperação, compatibilidade, suporte e implementação ainda precisam ser bem projetados.107108Mas a mudança básica é forte. Pare de pedir aos usuários que inventem e protejam segredos. Você permite que o dispositivo assine uma prova criptográfica vinculada ao seu domínio. Menos memória humana, menos phishing, menos redefinições de senha. Eu diria que vale a pena levá-los a sério.109110## Fontes111112- [MDN: Passkeys](https://developer.mozilla.org/en-US/docs/Web/Security/Authentication/Passkeys)113- [MDN: Web Authentication API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Authentication_API)114- [W3C: Web Authentication](https://www.w3.org/TR/webauthn-3/)115- [passkeys.dev](https://passkeys.dev/)116
:Passkey e WebAuthn: login sem senha, sem mágicalines 1-116 (END) — press q to close