Mais de 80% das violações de segurança corporativas continuam tendo como raiz senhas fracas, reutilizadas ou interceptadas por ataques de engenharia social e phishing. Em 2026, a indústria de tecnologia estabeleceu um novo padrão inegociável de segurança: o Fim das Senhas.
Com o suporte nativo a Passkeys (Chaves de Acesso) integrado ao Android, iOS, macOS e Windows 11, os usuários podem autenticar-se utilizando a biometria do próprio dispositivo (Face ID, impressão digital ou PIN local) sem que nenhuma senha jamais trafegue pela internet.
Neste tutorial prático, você aprenderá a implementar o fluxo completo de registro e autenticação de Passkeys utilizando o Next.js (App Router) e a biblioteca oficial SimpleWebAuthn.
1. Como Funciona a Criptografia Assimétrica do WebAuthn
Diferente de um sistema com senha onde o servidor guarda uma cópia (ou hash) do segredo, o padrão WebAuthn utiliza criptografia de chave pública/privada:
[ NAVEGADOR DO USUÁRIO ] [ SEU SERVIDOR NEXT.JS ]
│ │
│ 1. Solicita Opções de Registro │
│─────────────────────────────────────────────►│
│ │
│ 2. Envia Desafio Criptográfico (Challenge) │
│◄─────────────────────────────────────────────│
│ │
▼ │
[ BIOMETRIA / HARDWARE ] │
Gera Par de Chaves: │
- Chave Privada (Fica trancada no chip de segurança) │
- Chave Pública (Assina o desafio) │
│ │
│ 3. Envia Chave Pública + Assinatura │
│─────────────────────────────────────────────►│
│ │
│ 4. Salva Chave Pública
│ no Banco de Dados
O servidor armazena apenas a chave pública. Mesmo que seu banco de dados seja comprometido por um hacker, nenhuma credencial utilizável é exposta!
2. Passo a Passo: Configuração no Next.js
Instalando as Dependências
Em seu projeto Next.js, instale os pacotes oficializados para cliente e servidor:
npm install @simplewebauthn/server @simplewebauthn/browser
Passo 2: Rota da API para Gerar o Desafio de Registro
Crie a rota src/app/api/auth/register-options/route.ts:
import { NextResponse } from 'next/server';
import { generateRegistrationOptions } from '@simplewebauthn/server';
// Em produção, recupere os dados do usuário autenticado pela sessão
export async function GET() {
const user = {
id: 'user_123456789',
username: 'cliente@fymax.com.br',
displayName: 'Evandro Carvalho',
};
const options = await generateRegistrationOptions({
rpName: 'Fymax Sentinel Platform',
rpID: process.env.NODE_ENV === 'production' ? 'landingfymax.com.br' : 'localhost',
userID: new TextEncoder().encode(user.id),
userName: user.username,
userDisplayName: user.displayName,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'preferred',
userVerification: 'preferred',
},
});
// IMPORTANTE: Salve 'options.challenge' na sessão/cookie do usuário para validação posterior
return NextResponse.json(options);
}
Passo 3: Rota da API para Validar a Resposta do Hardware
Crie a rota src/app/api/auth/verify-registration/route.ts:
import { NextResponse } from 'next/server';
import { verifyRegistrationResponse } from '@simplewebauthn/server';
export async function POST(request: Request) {
const body = await request.json();
const expectedChallenge = 'desafio_salvo_na_sessao'; // Recupere da sessão segura
const verification = await verifyRegistrationResponse({
response: body,
expectedChallenge,
expectedOrigin: process.env.NODE_ENV === 'production'
? 'https://landingfymax.com.br'
: 'http://localhost:3000',
expectedRPID: process.env.NODE_ENV === 'production' ? 'landingfymax.com.br' : 'localhost',
});
if (verification.verified && verification.registrationInfo) {
const { credential } = verification.registrationInfo;
// Salve a credencial no banco de dados vinculada ao usuário:
// credential.id, credential.publicKey, credential.counter
return NextResponse.json({ success: true, message: 'Passkey cadastrada com sucesso!' });
}
return NextResponse.json({ success: false, error: 'Falha na validação biométrica' }, { status: 400 });
}
Passo 4: O Botão no Front-end (React Client Component)
Crie o componente de ativação da Passkey em src/components/RegisterPasskeyButton.tsx:
'use client';
import { startRegistration } from '@simplewebauthn/browser';
import { useState } from 'react';
export default function RegisterPasskeyButton() {
const [status, setStatus] = useState<string>('');
async function handleRegisterPasskey() {
try {
setStatus('Solicitando permissão biométrica...');
// 1. Obter opções e desafio do backend
const optionsRes = await fetch('/api/auth/register-options');
const options = await optionsRes.json();
// 2. Chamar o hardware nativo do dispositivo (Touch ID / Face ID)
const regResponse = await startRegistration({ optionsJSON: options });
// 3. Enviar a credencial gerada para validação no servidor
const verifyRes = await fetch('/api/auth/verify-registration', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(regResponse),
});
const result = await verifyRes.json();
if (result.success) {
setStatus('✅ Passkey ativada! Sua conta agora está blindada contra phishing.');
} else {
setStatus('❌ Erro na validação.');
}
} catch (err: any) {
setStatus(`❌ Falha ou cancelado pelo usuário: ${err.message}`);
}
}
return (
<div style={{ padding: '1rem', border: '1px solid var(--border)', borderRadius: '0.75rem' }}>
<button
onClick={handleRegisterPasskey}
style={{
background: 'var(--accent)',
color: '#fff',
padding: '0.75rem 1.5rem',
borderRadius: '0.5rem',
border: 'none',
fontWeight: 'bold',
cursor: 'pointer'
}}
>
🔐 Ativar Login com Biometria (Passkey)
</button>
{status && <p style={{ marginTop: '0.75rem', fontSize: '0.9rem' }}>{status}</p>}
</div>
);
}
Conclusão: Uma Experiência Imbatível para o Usuário
Implementar Passkeys elimina atritos: o usuário não precisa lembrar combinações complexas de caracteres e seu sistema ganha proteção criptográfica de nível militar.
Quer garantir que sua aplicação ou landing page ofereça o que há de mais avançado em segurança e conversão? Conte com a equipe de engenharia da Landingfymax. Conheça nossos serviços de desenvolvimento profissional.




