Autenticação Multifator
Fatores TOTP — um aplicativo autenticador — mais o desafio que eleva uma sessão
de aal1 para aal2.
Cadastrando um fator
Seção intitulada “Cadastrando um fator”const { factor, totp, recoveryCodes } = await client.auth.mfa.enroll({ friendlyName: "Phone"});
showQrCode(totp.uri); // otpauth://… — what the authenticator scansif (recoveryCodes) showRecoveryCodes(recoveryCodes);Exiba os códigos de recuperação uma única vez e nunca mais. Apenas os hashes são armazenados,
portanto nada poderá exibi-los mais tarde. Eles vêm com o primeiro fator da conta.
Adicionar outro fator mantém os códigos que a conta já tem, e
recoveryCodes é null. Iniciar um cadastro e abandoná-lo nunca os afeta.
Para substituí-los, depois de usar vários ou perder a impressão, chame
regenerateRecoveryCodes() a partir de uma sessão aal2. Os códigos antigos deixam de funcionar:
const { recoveryCodes } = await client.auth.mfa.regenerateRecoveryCodes();Alguém que perdeu tanto o autenticador quanto os códigos é deixado entrar de volta por um
administrador: client.admin.resetMfa(uid) (DELETE /api/admin/users/:uid/mfa,
users:write) remove os fatores e códigos da conta e encerra suas sessões,
de modo que a senha faz login novamente sem um segundo fator. Na 0.23 todo cadastro
retorna um novo conjunto de códigos que substitui o antigo, e nem
regenerateRecoveryCodes() nem resetMfa existem.
O fator não pode ser usado até que o usuário comprove que seu autenticador gerou um código a partir desse segredo:
await client.auth.mfa.verify(factor.id, "418293");Fazendo login com MFA
Seção intitulada “Fazendo login com MFA”Um login em uma conta com MFA cadastrado não retorna nenhuma sessão. Ele é recusado com 401 MFA_REQUIRED, e os details do erro trazem um mfaToken e os factors verificados da conta. Passe esse token para challenge e verifyChallenge para obter a sessão:
import { RebaseApiError } from "@rebasepro/client";
type MfaRequired = { mfaToken: string; factors: { id: string; factorType: string; friendlyName?: string }[];};
try { await client.auth.signInWithEmail(email, password);} catch (e) { if (!(e instanceof RebaseApiError) || e.code !== "MFA_REQUIRED") throw e; const { mfaToken, factors } = e.details as MfaRequired;
const { challengeId } = await client.auth.mfa.challenge(factors[0].id, { mfaToken });
// A TOTP code, or one of the recovery codes. const { user } = await client.auth.mfa.verifyChallenge(challengeId, "418293", { mfaToken });}O mfaToken é enviado apenas nessas duas requisições e nunca é instalado no cliente. verifyChallenge emite a sessão aal2, este cliente a adota e emite SIGNED_IN como em qualquer outro login. O mfaToken expira cinco minutos após o login que o retornou, e um desafio cinco minutos após ser aberto. Um desafio cujas tentativas atingiram o limite é invalidado pelo resto de sua duração — caso contrário, um desafio aberto permitiria tentativas ilimitadas para adivinhar os seis dígitos.
Sem mfaToken, as duas chamadas elevam a sessão que este cliente já mantém de aal1 para aal2.
Removendo um fator
Seção intitulada “Removendo um fator”await client.auth.mfa.unenroll(factorId);Depois que um fator é verificado, isso requer uma sessão aal2, para que um token
aal1 roubado não possa desativar o MFA; um primeiro cadastro inacabado é removido a
partir de qualquer sessão. Remover o último fator verificado também
descarta os códigos de recuperação.
Próximos Passos
Seção intitulada “Próximos Passos”- Autenticação — Login, sessões e o restante do
client.auth - Endpoints de autenticação — As rotas HTTP por trás do cadastro e do desafio