spinny:~/writing $ vim passkeys-webauthn-passwordless-authentication.md
1~2As 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.3~4O 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.5~6## O que realmente acontece7~8Um passkey é uma credencial baseada em WebAuthn. Quando o usuário o cria, o dispositivo gera um par de chaves:9~10- uma chave privada, que permanece no dispositivo ou no gerenciador de senhas;11- uma chave pública, que o servidor pode salvar.12~13Ao 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.14~15Essa é 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.16~17## O navegador funciona como uma ponte18~19No navegador, os dois API principais são:20~21- `navigator.credentials.create()` para criar um passkey;22- `navigator.credentials.get()` para usá-lo durante o login.23~24Mas 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.25~26A parte do cliente deve ser quase chata:27~28```typescript29const options = await fetch('/api/passkeys/login/options').then((r) => r.json());30~31const credential = await navigator.credentials.get({32 publicKey: PublicKeyCredential.parseRequestOptionsFromJSON(options),33});34~35await fetch('/api/passkeys/login/verify', {36 method: 'POST',37 headers: { 'Content-Type': 'application/json' },38 body: JSON.stringify(credential?.toJSON()),39});40```41~42Se 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.43~44## O que salvar no banco de dados45~46Não há necessidade de salvar metade do mundo. Geralmente é suficiente:47~48- 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.55~56Uma tabela mínima pode ser assim:57~58```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```69~70Então eu adicionaria registros de auditoria e notificações: se alguém criar um novo passkey na minha conta, quero saber sobre isso.71~72## UX é mais importante do que demonstração73~74A demonstração de um passkey é sempre linda: você clica, Face ID, você entra. O produto real é mais complicado.75~76Algué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.77~78É por isso que eu não começaria com “a partir de hoje não há mais senhas para todos”. Eu começaria assim:79~801. 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.85~86O texto na interface deve ser simples. "Usar a tela de bloqueio do seu dispositivo" é melhor do que "autenticar com uma credencial de residente FIDO2".87~88## Erros que eu evitaria89~90Não gere desafios ao cliente. O desafio é criado no servidor e deve ser verificado apenas uma vez.91~92Não confie apenas no ID da credencial. Você precisa verificar assinatura, desafio, origem e Relying Party ID.93~94Nã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”.95~96Nã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.97~98## Passkey-primeiro ou passkey-amigável?99~100Para 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.101~102A 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.103~104## Conclusão105~106Os 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.107~108Mas 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.109~110## Fontes111~112- [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~
NORMAL · passkeys-webauthn-passwordless-authentication.md [readonly]116 lines · :q to close