Cadastrar passkey e confirmar por biometria
Cadastra uma passkey no aparelho do cliente logado e emite um token de curta duração para confirmar ações sensíveis.
Duas coisas acontecem aqui, ambas exigem um cliente já logado (Authorization: Bearer) e seguem o mesmo molde de duas chamadas, begin e finish.
Cadastrar a passkey liga o aparelho à conta, para os próximos logins sem senha (veja Login com passkey). Confirmar por biometria (step-up) prova, naquele momento, que a pessoa na frente da tela é o dono da conta. Hoje o token de step-up é exigido na aprovação de cotações de organizações corporativas que ativaram essa regra; sem ele a resposta é 403 step_up_required.
/api/v1/auth/webauthn/register/beginAutenticadaIniciar o cadastro da passkey
Não recebe corpo. O options.publicKey vai para navigator.credentials.create.
Exemplo de requisição
curl -X POST "$BASE_URL/api/v1/auth/webauthn/register/begin" \
-H "Authorization: Bearer $TOKEN"Resposta
{
"ceremony_id": "647bb41f-0aec-46ac-a2aa-9396f65ea311",
"options": {
"publicKey": {
"rp": {
"name": "Minha Loja",
"id": "minhaloja.io.venddor.com.br"
},
"user": {
"id": "M2YwYzJh...",
"name": "maria.souza@example.com",
"displayName": "Maria Souza"
},
"challenge": "Vb2n1c...",
"pubKeyCredParams": [
{
"type": "public-key",
"alg": -7
}
],
"timeout": 300000
}
}
}Campos da resposta
ceremony_iduuidfinish.optionsobjectrp, user, challenge, pubKeyCredParams, timeout)./api/v1/auth/webauthn/register/finishAutenticadaConcluir o cadastro da passkey
Corpo da requisição
ceremony_iduuidobrigatóriobegin.credentialobjectobrigatórionavigator.credentials.create serializado em JSON.nicknamestringiPhone da Maria).Exemplo de requisição
curl -X POST "$BASE_URL/api/v1/auth/webauthn/register/finish" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ceremony_id": "647bb41f-0aec-46ac-a2aa-9396f65ea311",
"nickname": "iPhone da Maria",
"credential": {
"id": "AQIDBAUG...",
"rawId": "AQIDBAUG...",
"type": "public-key",
"response": {
"clientDataJSON": "eyJ0eXBl...",
"attestationObject": "o2NmbXRk..."
}
}
}'Resposta
{
"credential": {
"id": "9d3b5c10-2f7e-4a38-8d51-0c7e6b1a2f44",
"nickname": "iPhone da Maria",
"rp_id": "minhaloja.io.venddor.com.br",
"last_used_at": null,
"created_at": "2026-10-11T20:41:07Z"
}
}Campos da resposta
credential.iduuidDELETE /auth/webauthn/credentials/{id}.credential.nicknamestringcredential.rp_idstringcredential.last_used_atstringnull se nunca foi usada.credential.created_atstring/api/v1/auth/webauthn/stepup/beginAutenticadaIniciar a confirmação por biometria
Sem corpo. Responde no mesmo formato do login/begin, mas restrito às passkeys do próprio usuário.
curl -X POST "$BASE_URL/api/v1/auth/webauthn/stepup/begin" \
-H "Authorization: Bearer $TOKEN"{
"ceremony_id": "647bb41f-0aec-46ac-a2aa-9396f65ea311",
"options": {
"publicKey": {
"challenge": "qrTUyCAThPPHs-5tfQvPMVj_nlVvoKMx9mbcVZK11v4",
"timeout": 300000,
"rpId": "minhaloja.io.venddor.com.br"
}
}
}/api/v1/auth/webauthn/stepup/finishAutenticadaConcluir a confirmação e obter o token de step-up
Corpo da requisição
ceremony_iduuidobrigatóriostepup/begin.credentialobjectobrigatórionavigator.credentials.get em JSON.curl -X POST "$BASE_URL/api/v1/auth/webauthn/stepup/finish" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ceremony_id": "647bb41f-0aec-46ac-a2aa-9396f65ea311",
"credential": {
"id": "AQIDBAUG...",
"rawId": "AQIDBAUG...",
"type": "public-key",
"response": {
"clientDataJSON": "eyJ0eXBl...",
"authenticatorData": "SZYN5Y...",
"signature": "MEUCIQ...",
"userHandle": "M2YwYzJh..."
}
}
}'{
"step_up_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2026-10-11T20:52:00Z"
}Campos da resposta
step_up_tokenstringX-Step-Up-Token.expires_atstringErros
| Status | Quando | Exemplo de corpo |
|---|---|---|
| 400 | register/finish com corpo inválido, prova inválida ou cerimônia expirada. | {"error":"registration failed","detail":"..."} |
| 401 | Sem token de acesso, ou token inválido. | {"error":"authentication required"} |
| 401 | stepup/finish com prova inválida ou cerimônia expirada. | {"error":"step-up failed","detail":"..."} |
| 412 | stepup/begin para um usuário sem nenhuma passkey. | {"error":"no_passkey"} |
| 429 | Limite de requisições da família /auth/. | {"error":"rate limit exceeded","detail":"too many requests, please try again later"} |
| 500 | Falha ao gerar o desafio. | {"error":"failed to begin registration","detail":"..."} |