WebAuthn (Web Authentication API) é um padrão W3C que permite autenticação segura sem senha usando criptografia de chave pública. Em vez de senhas, os usuários registram-se e autenticam-se usando autenticadores baseados em hardware (como leitores de impressão digital, Face ID, YubiKeys, etc.) ou autenticadores de plataforma (integrados, como o Touch ID).
Veja abaixo como tratar o Registro e a Autenticação utilizando um cliente Javascript.
Como funciona o WebAuthn Registration
O usuário inicia o registro:
O usuário fornece um nome de usuário e clica em Registrar.
O navegador solicita as Options ao servidor:
O frontend faz uma requisição POST para obter as opções de registro.
O Navegador Cria as Credenciais:
Utilizando a API navigator.credentials.create() por meio de SimpleWebAuthnBrowser.startRegistration(), uma credencial é criada.
O Servidor Verifica o Registro:
O navegador envia a credencial de volta ao servidor.
O servidor verifica o registro e armazena a chave pública para esse usuário.
O componente TsgcWSAPIServer_WebAuthn possui um arquivo html para testar o protocolo WebAuthn. Este arquivo HTML contém uma interface mínima e JavaScript para interagir com WebAuthn.
Tutorial de sgcWebAuthn.html
Visão geral da estrutura:
Username Input: Captura o identificador do usuário.
Botões:
Register – inicia o registro WebAuthn.
Authenticate – inicia o login (tratado de forma similar).
Debug Console: Exibe informações de depuração em tempo real (JSON do WebAuthn).
1. UI HTML para Entrada
<input type="text" id="username" name="username" autocomplete="username webauthn" />
<button id="btnRegBegin"><strong>Register</strong></button>
2. JavaScript: Handler de clique do botão
document.querySelector('#btnRegBegin').addEventListener('click', async () => {
const username = document.getElementById("username").value;
if (username == "") {
document.getElementById('Error').innerText = 'Please enter a username to register';
return;
}
const resp = await fetch('<#webauthn_registration_options>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, algorithms: [] })
});
const options = await resp.json();
const attResp = await startRegistration(options); // WebAuthn API
3. Resposta do servidor (endpoint simulado em HTML)
fetch('/sgcWebAuthn/Registration/Options', ...)
fetch('/sgcWebAuthn/Registration/Verify', ...)
4. Finalizando o Registro
const verificationResp = await fetch('/webauthn/register/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(attResp)
});
const verificationJSON = await verificationResp.json();
if (verificationJSON && verificationJSON.verified) {
document.getElementById('Success').innerHTML = `Authenticator registered!`;
}
Como Funciona a Autenticação WebAuthn
O usuário inicia a autenticação:
O usuário fornece um nome de usuário e clica em Registrar.
O navegador solicita as Options ao servidor:
O frontend faz uma requisição POST para obter as opções de autenticação.
O Navegador Cria as Credenciais:
Utilizando a API navigator.credentials.get() via SimpleWebAuthnBrowser.startAuthentication().
O servidor verifica a autenticação:
O navegador envia a credencial de volta ao servidor.
O servidor verifica o resultado assinado.
1. Configuração da Interface HTML
<div class="container">
<h1>WebAuthn Authentication Sample</h1>
<section id="userdata">
<label for="username">Username:</label>
<input type="text" id="username" name="username" autocomplete="username webauthn" autofocus />
</section>
<button id="btnAuthBegin"><strong>Authenticate</strong></button>
<p id="Success" class="success"></p>
<p id="Error" class="error"></p>
<details open>
<summary>Console</summary>
<textarea id="Debug"></textarea>
</details>
</div>
2. Obter as Authentication Options
Antes de chamar startAuthentication, você envia o nome de usuário ao servidor
const resp = await fetch('<#webauthn_authentication_options>', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: document.getElementById("username").value,
user_verification: 'preferred'
}),
});
O servidor responde com um objeto JSON que inclui:
{
"challenge": "base64url-encoded-random-string",
"allowCredentials": [
{
"id": "base64url-credential-id",
"type": "public-key"
}
],
"userVerification": "preferred",
"rpId": "yourdomain.com"
}
Isto é chamado de PublicKeyCredentialRequestOptions.
3. Receba a Resposta do Authenticator
O asseResp se parece com isto (simplificado):
{
"id": "credentialId",
"rawId": "base64url-encoded-id",
"response": {
"authenticatorData": "...",
"clientDataJSON": "...",
"signature": "...",
"userHandle": "..."
},
"type": "public-key",
"clientExtensionResults": {}
}
Esta resposta prova que o usuário:
4. Envie a Signed Authentication Response ao servidor
Depois que o usuário interage com seu autenticador (via startAuthentication()), você obtém um objeto de resposta em JavaScript.
const verificationResp = await fetch('/webauthn/authenticate/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(asseResp), // this is the signed response
});
5. Obtenha a Resposta do Servidor
O servidor responderá com um resultado como este:
{ "verified": true }
Ou se algo deu errado:
{ "verified": false, "error": "Invalid signature" }
E você o trata no código do seu frontend:
const result = await verificationResp.json();
if (result.verified) {
document.getElementById('Success').textContent = 'User authenticated!';
} else {
document.getElementById('Error').textContent = 'Authentication failed!';
}