Como adicionar a autenticação multifator ao seu app da Web
Este documento mostra como adicionar a autenticação multifator por SMS ao seu app da Web.
A autenticação multifator aumenta a segurança do app. Os invasores costumam comprometer as senhas e contas de redes sociais, mas é mais difícil interceptar uma mensagem de texto.
Antes de começar
Ative pelo menos um provedor compatível com a autenticação multifator. Todos os provedores são compatíveis com a autenticação multifator (MFA), exceto as autenticações por smartphone e a anônima e o Apple Game Center.
Ative as regiões em que você planeja usar a autenticação por SMS. O Identity Platform usa uma política de região de SMS de bloqueio total, que ajuda a criar projetos em um estado mais seguro por padrão.
Confirme se o app está verificando os e-mails do usuário. A autenticação multifator (MFA) requer verificação de e-mail. Isso impede que agentes mal-intencionados se inscrevam em um serviço com um e-mail que não tenham e bloqueiem o proprietário real adicionando um segundo fator.
Como usar multilocação
Se você estiver ativando a autenticação multifator para uso em um ambiente de multilocação, conclua as etapas a seguir (além das demais instruções deste documento):
No console do Google Cloud, selecione o locatário com que você quer trabalhar.
No código, defina o campo
tenantId
na instânciaAuth
como o ID do locatário. Exemplo:Versão 9 para a Web
import { getAuth } from "firebase/auth"; const auth = getAuth(app); auth.tenantId = "myTenantId1";
Versão 8 para a Web
firebase.auth().tenantId = 'myTenantId1';
Como ativar a autenticação multifator
Acesse a página MFA do Identity Platform no console do Google Cloud.
Acessar a página MFANa caixa Autenticação de vários fatores baseada em SMS, clique em Ativar.
Insira os números de telefone com os quais você testará seu aplicativo. Ainda que seja opcional, é altamente recomendável registrar números de telefone de teste para evitar a limitação durante o desenvolvimento.
Se você ainda não autorizou o domínio do seu aplicativo, adicione-o à lista de permissões clicando em Adicionar domínio à direita.
Clique em Save.
Como escolher um padrão de inscrição
É possível escolher se o app requer autenticação multifator e como e quando registrar os usuários. Alguns padrões comuns incluem:
Registrar o segundo fator do usuário como parte do processo. Use esse método se o app exigir autenticação multifator para todos os usuários.
Oferecer uma opção que pode ser ignorada para registrar um segundo fator durante o processo. Os apps que quiserem incentivar, mas não exigirem, a autenticação multifator terão essa abordagem.
Permitir a adição de um segundo fator na página de gerenciamento da conta ou no perfil do usuário, em vez da tela de inscrição. Isso minimiza o atrito durante o processo de registro, ao mesmo tempo que disponibiliza a autenticação multifator para usuários que se preocupam com a segurança.
Exigir a adição de um segundo fator de maneira incremental quando o usuário quiser acessar recursos com requisitos de segurança aprimorados.
Como configurar o verificador reCAPTCHA
Antes de enviar códigos SMS, é necessário configurar um verificador reCAPTCHA. O Identity Platform usa o reCAPTCHA para evitar abusos, garantindo que as solicitações de verificação de número de telefone sejam provenientes de um dos domínios permitidos do app.
Não é preciso configurar manualmente um cliente reCAPTCHA. O objeto
RecaptchaVerifier
do SDK do cliente cria e inicializa automaticamente todos os secrets
e chaves de cliente necessários.
Como usar o reCAPTCHA invisível
O objeto RecaptchaVerifier
é compatível
com reCAPTCHA invisível,
que geralmente verifica o usuário sem exigir nenhuma interação. Para usar um
reCAPTCHA invisível, crie um RecaptchaVerifier
com o parâmetro size
definido
como invisible
e especifique o ID do elemento da IU que inicia o registro de vários
fatores:
Versão 9 para a Web
import { RecaptchaVerifier } from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier("sign-in-button", {
"size": "invisible",
"callback": function(response) {
// reCAPTCHA solved, you can proceed with
// phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
}
}, auth);
Versão 8 para a Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
'size': 'invisible',
'callback': function(response) {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
}
});
Como usar o widget reCAPTCHA
Para usar um widget reCAPTCHA visível, crie um elemento HTML para conter
o widget e, em seguida, crie um objeto RecaptchaVerifier
com o ID do contêiner da
IU. Também é possível definir callbacks que são invocados quando o
reCAPTCHA é resolvido ou expira:
Versão 9 para a Web
import { RecaptchaVerifier } from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier(
"recaptcha-container",
// Optional reCAPTCHA parameters.
{
"size": "normal",
"callback": function(response) {
// reCAPTCHA solved, you can proceed with
// phoneAuthProvider.verifyPhoneNumber(...).
onSolvedRecaptcha();
},
"expired-callback": function() {
// Response expired. Ask user to solve reCAPTCHA again.
// ...
}
}, auth
);
Versão 8 para a Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier(
'recaptcha-container',
// Optional reCAPTCHA parameters.
{
'size': 'normal',
'callback': function(response) {
// reCAPTCHA solved, you can proceed with phoneAuthProvider.verifyPhoneNumber(...).
// ...
onSolvedRecaptcha();
},
'expired-callback': function() {
// Response expired. Ask user to solve reCAPTCHA again.
// ...
}
});
Como pré-renderizar o reCAPTCHA
Você pode pré-renderizar o reCAPTCHA antes de iniciar o registro de dois fatores:
Versão 9 para a Web
recaptchaVerifier.render()
.then(function (widgetId) {
window.recaptchaWidgetId = widgetId;
});
Versão 8 para a Web
recaptchaVerifier.render()
.then(function(widgetId) {
window.recaptchaWidgetId = widgetId;
});
Quando render()
é resolvido, você recebe o ID do widget do reCAPTCHA, que
pode ser usado para fazer chamadas para a
API reCAPTCHA:
var recaptchaResponse = grecaptcha.getResponse(window.recaptchaWidgetId);
O RecaptchaVerifier remove essa lógica com o método de verificação, para que você não processe a variável grecaptcha
diretamente.
Como registrar um segundo fator
Para registrar um novo fator secundário para um usuário:
Reautentique o usuário.
Peça ao usuário para inserir o número de telefone.
Inicialize o verificador reCAPTCHA, conforme ilustrado na seção anterior. Pule esta etapa se uma instância do RecaptchaVerifier já estiver configurada:
Versão 9 para a Web
import { RecaptchaVerifier } from "firebase/auth"; const recaptchaVerifier = new RecaptchaVerifier('recaptcha-container-id', undefined, auth);
Versão 8 para a Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
Disponibilize uma sessão de vários fatores para o usuário:
Versão 9 para a Web
import { multiFactor } from "firebase/auth"; multiFactor(user).getSession().then(function (multiFactorSession) { // ... });
Versão 8 para a Web
user.multiFactor.getSession().then(function(multiFactorSession) { // ... })
Inicialize um objeto
PhoneInfoOptions
com o número de telefone do usuário e a sessão de vários fatores:Versão 9 para a Web
// Specify the phone number and pass the MFA session. const phoneInfoOptions = { phoneNumber: phoneNumber, session: multiFactorSession };
Versão 8 para a Web
// Specify the phone number and pass the MFA session. var phoneInfoOptions = { phoneNumber: phoneNumber, session: multiFactorSession };
Envie um código de verificação ao smartphone do usuário:
Versão 9 para a Web
import { PhoneAuthProvider } from "firebase/auth"; const phoneAuthProvider = new PhoneAuthProvider(auth); phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function (verificationId) { // verificationId will be needed to complete enrollment. });
Versão 8 para a Web
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider(); // Send SMS verification code. return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function(verificationId) { // verificationId will be needed for enrollment completion. })
Não é obrigatório, mas recomendamos informar aos usuários antecipadamente que eles receberão uma mensagem SMS e quais taxas padrão serão aplicadas.
Se a solicitação falhar, redefina o reCAPTCHA e repita a etapa anterior para que o usuário possa tentar novamente.
verifyPhoneNumber()
redefinirá o reCAPTCHA automaticamente ao gerar um erro, já que os tokens de reCAPTCHA são usados apenas uma vez.Versão 9 para a Web
recaptchaVerifier.clear();
Versão 8 para a Web
recaptchaVerifier.clear();
Após o envio do código SMS, peça ao usuário para fazer a verificação dele:
Versão 9 para a Web
// Ask user for the verification code. Then: const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
Versão 8 para a Web
// Ask user for the verification code. Then: var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
Inicialize um objeto
MultiFactorAssertion
com oPhoneAuthCredential
:Versão 9 para a Web
import { PhoneMultiFactorGenerator } from "firebase/auth"; const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
Versão 8 para a Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
Conclua o registro. Se quiser, especifique um nome de exibição para o segundo fator. Isso é útil para usuários com vários fatores, já que o número de telefone é mascarado durante o fluxo de autenticação (por exemplo, +1******1234).
Versão 9 para a Web
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. multiFactor(user).enroll(multiFactorAssertion, "My personal phone number");
Versão 8 para a Web
// Complete enrollment. This will update the underlying tokens // and trigger ID token change listener. user.multiFactor.enroll(multiFactorAssertion, 'My personal phone number');
O código abaixo mostra um exemplo completo de registro de um segundo fator:
Versão 9 para a Web
import {
multiFactor, PhoneAuthProvider, PhoneMultiFactorGenerator,
RecaptchaVerifier
} from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier('recaptcha-container-id', undefined, auth);
multiFactor(user).getSession()
.then(function (multiFactorSession) {
// Specify the phone number and pass the MFA session.
const phoneInfoOptions = {
phoneNumber: phoneNumber,
session: multiFactorSession
};
const phoneAuthProvider = new PhoneAuthProvider(auth);
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier);
}).then(function (verificationId) {
// Ask user for the verification code. Then:
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
// Complete enrollment.
return multiFactor(user).enroll(multiFactorAssertion, mfaDisplayName);
});
Versão 8 para a Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
user.multiFactor.getSession().then(function(multiFactorSession) {
// Specify the phone number and pass the MFA session.
var phoneInfoOptions = {
phoneNumber: phoneNumber,
session: multiFactorSession
};
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code.
return phoneAuthProvider.verifyPhoneNumber(
phoneInfoOptions, recaptchaVerifier);
})
.then(function(verificationId) {
// Ask user for the verification code.
var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete enrollment.
return user.multiFactor.enroll(multiFactorAssertion, mfaDisplayName);
});
Parabéns! Você registrou um segundo fator de autenticação para um usuário.
Como fazer login dos usuários com um segundo fator
Para fazer login de um usuário com verificação por SMS de dois fatores:
Faça login do usuário com o primeiro fator e detecte o erro
auth/multi-factor-auth-required
. Esse erro contém um resolvedor, dicas sobre os dois fatores registrados e uma sessão que mostra que o usuário foi autenticado com o primeiro fator.Por exemplo, se o primeiro fator do usuário for um e-mail e uma senha:
Versão 9 para a Web
import { getAuth, getMultiFactorResolver} from "firebase/auth"; const auth = getAuth(); signInWithEmailAndPassword(auth, email, password) .then(function (userCredential) { // User successfully signed in and is not enrolled with a second factor. }) .catch(function (error) { if (error.code == 'auth/multi-factor-auth-required') { // The user is a multi-factor user. Second factor challenge is required. resolver = getMultiFactorResolver(auth, error); // ... } else if (error.code == 'auth/wrong-password') { // Handle other errors such as wrong password. } });
Versão 8 para a Web
firebase.auth().signInWithEmailAndPassword(email, password) .then(function(userCredential) { // User successfully signed in and is not enrolled with a second factor. }) .catch(function(error) { if (error.code == 'auth/multi-factor-auth-required') { // The user is a multi-factor user. Second factor challenge is required. resolver = error.resolver; // ... } else if (error.code == 'auth/wrong-password') { // Handle other errors such as wrong password. } ... });
Se o primeiro fator do usuário for um provedor federado, como OAuth, SAML ou OIDC, capture o erro depois de chamar
signInWithPopup()
ousignInWithRedirect()
.Se o usuário tiver vários fatores secundários registrados, pergunte a ele qual usar:
Versão 9 para a Web
// Ask user which second factor to use. // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber // You can get the display name via resolver.hints[selectedIndex].displayName if (resolver.hints[selectedIndex].factorId === PhoneMultiFactorGenerator.FACTOR_ID) { // User selected a phone second factor. // ... } else if (resolver.hints[selectedIndex].factorId === TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Versão 8 para a Web
// Ask user which second factor to use. // You can get the masked phone number via resolver.hints[selectedIndex].phoneNumber // You can get the display name via resolver.hints[selectedIndex].displayName if (resolver.hints[selectedIndex].factorId === firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) { // User selected a phone second factor. // ... } else if (resolver.hints[selectedIndex].factorId === firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) { // User selected a TOTP second factor. // ... } else { // Unsupported second factor. }
Inicialize o verificador reCAPTCHA, conforme ilustrado na seção anterior. Pule esta etapa se uma instância do RecaptchaVerifier já estiver configurada:
Versão 9 para a Web
import { RecaptchaVerifier } from "firebase/auth"; recaptchaVerifier = new RecaptchaVerifier('recaptcha-container-id', undefined, auth);
Versão 8 para a Web
var recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container-id');
Inicialize um objeto
PhoneInfoOptions
com o número de telefone do usuário e a sessão de vários fatores. Esses valores estão contidos no objetoresolver
passado ao erroauth/multi-factor-auth-required
:Versão 9 para a Web
const phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };
Versão 8 para a Web
var phoneInfoOptions = { multiFactorHint: resolver.hints[selectedIndex], session: resolver.session };
Envie um código de verificação ao smartphone do usuário:
Versão 9 para a Web
// Send SMS verification code. const phoneAuthProvider = new PhoneAuthProvider(auth); phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function (verificationId) { // verificationId will be needed for sign-in completion. });
Versão 8 para a Web
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider(); // Send SMS verification code. return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier) .then(function(verificationId) { // verificationId will be needed for sign-in completion. })
Se a solicitação falhar, redefina o reCAPTCHA e repita a etapa anterior para que o usuário possa tentar novamente:
Versão 9 para a Web
recaptchaVerifier.clear();
Versão 8 para a Web
recaptchaVerifier.clear();
Após o envio do código SMS, peça ao usuário para fazer a verificação dele:
Versão 9 para a Web
const cred = PhoneAuthProvider.credential(verificationId, verificationCode);
Versão 8 para a Web
// Ask user for the verification code. Then: var cred = firebase.auth.PhoneAuthProvider.credential(verificationId, verificationCode);
Inicialize um objeto
MultiFactorAssertion
com oPhoneAuthCredential
:Versão 9 para a Web
const multiFactorAssertion = PhoneMultiFactorGenerator.assertion(cred);
Versão 8 para a Web
var multiFactorAssertion = firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
Chame
resolver.resolveSignIn()
para concluir a autenticação secundária. Em seguida, você pode acessar o resultado do login original, que inclui os dados padrão do provedor e as credenciais de autenticação:Versão 9 para a Web
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(multiFactorAssertion) .then(function (userCredential) { // userCredential will also contain the user, additionalUserInfo, optional // credential (null for email/password) associated with the first factor sign-in. // For example, if the user signed in with Google as a first factor, // userCredential.additionalUserInfo will contain data related to Google // provider that the user signed in with. // - user.credential contains the Google OAuth credential. // - user.credential.accessToken contains the Google OAuth access token. // - user.credential.idToken contains the Google OAuth ID token. });
Versão 8 para a Web
// Complete sign-in. This will also trigger the Auth state listeners. resolver.resolveSignIn(multiFactorAssertion) .then(function(userCredential) { // userCredential will also contain the user, additionalUserInfo, optional // credential (null for email/password) associated with the first factor sign-in. // For example, if the user signed in with Google as a first factor, // userCredential.additionalUserInfo will contain data related to Google provider that // the user signed in with. // user.credential contains the Google OAuth credential. // user.credential.accessToken contains the Google OAuth access token. // user.credential.idToken contains the Google OAuth ID token. });
O código abaixo mostra um exemplo completo de login em um usuário de vários fatores:
Versão 9 para a Web
import {
getAuth,
getMultiFactorResolver,
PhoneAuthProvider,
PhoneMultiFactorGenerator,
RecaptchaVerifier,
signInWithEmailAndPassword
} from "firebase/auth";
const recaptchaVerifier = new RecaptchaVerifier('recaptcha-container-id', undefined, auth);
const auth = getAuth();
signInWithEmailAndPassword(auth, email, password)
.then(function (userCredential) {
// User is not enrolled with a second factor and is successfully
// signed in.
// ...
})
.catch(function (error) {
if (error.code == 'auth/multi-factor-auth-required') {
const resolver = getMultiFactorResolver(auth, error);
// Ask user which second factor to use.
if (resolver.hints[selectedIndex].factorId ===
PhoneMultiFactorGenerator.FACTOR_ID) {
const phoneInfoOptions = {
multiFactorHint: resolver.hints[selectedIndex],
session: resolver.session
};
const phoneAuthProvider = new PhoneAuthProvider(auth);
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function (verificationId) {
// Ask user for the SMS verification code. Then:
const cred = PhoneAuthProvider.credential(
verificationId, verificationCode);
const multiFactorAssertion =
PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
return resolver.resolveSignIn(multiFactorAssertion)
})
.then(function (userCredential) {
// User successfully signed in with the second factor phone number.
});
} else if (resolver.hints[selectedIndex].factorId ===
TotpMultiFactorGenerator.FACTOR_ID) {
// Handle TOTP MFA.
// ...
} else {
// Unsupported second factor.
}
} else if (error.code == 'auth/wrong-password') {
// Handle other errors such as wrong password.
}
});
Versão 8 para a Web
var resolver;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(userCredential) {
// User is not enrolled with a second factor and is successfully signed in.
// ...
})
.catch(function(error) {
if (error.code == 'auth/multi-factor-auth-required') {
resolver = error.resolver;
// Ask user which second factor to use.
if (resolver.hints[selectedIndex].factorId ===
firebase.auth.PhoneMultiFactorGenerator.FACTOR_ID) {
var phoneInfoOptions = {
multiFactorHint: resolver.hints[selectedIndex],
session: resolver.session
};
var phoneAuthProvider = new firebase.auth.PhoneAuthProvider();
// Send SMS verification code
return phoneAuthProvider.verifyPhoneNumber(phoneInfoOptions, recaptchaVerifier)
.then(function(verificationId) {
// Ask user for the SMS verification code.
var cred = firebase.auth.PhoneAuthProvider.credential(
verificationId, verificationCode);
var multiFactorAssertion =
firebase.auth.PhoneMultiFactorGenerator.assertion(cred);
// Complete sign-in.
return resolver.resolveSignIn(multiFactorAssertion)
})
.then(function(userCredential) {
// User successfully signed in with the second factor phone number.
});
} else if (resolver.hints[selectedIndex].factorId ===
firebase.auth.TotpMultiFactorGenerator.FACTOR_ID) {
// Handle TOTP MFA.
// ...
} else {
// Unsupported second factor.
}
} else if (error.code == 'auth/wrong-password') {
// Handle other errors such as wrong password.
} ...
});
Parabéns! Você fez login com sucesso usando uma autenticação multifator.
A seguir
- Gerencie usuários de vários fatores programaticamente com o SDK Admin.