Autenticar com o Firebase e um número de telefone usando JavaScript

Use o Firebase Authentication para fazer o login de um usuário. Basta enviar uma mensagem SMS para o telefone dele. O usuário faz login com um código de uso único contido na mensagem SMS.

A maneira mais fácil de adicionar o login com número de telefone ao app é usar a FirebaseUI. Ela inclui um widget drop-in que implementa fluxos para logins com número de telefone, bem como logins por senha ou federados. Este documento descreve como implementar um fluxo de login com número de telefone pelo SDK do Firebase.

Antes de começar

Copie o snippet de inicialização do Console do Firebase para o projeto, conforme descrito na página Adicionar o Firebase a seu projeto do JavaScript, se ainda não tiver feito isso.

Preocupações com segurança

A autenticação usando apenas um número de telefone é conveniente, porém, menos segura do que os outros métodos disponíveis, já que um número de telefone pode ser facilmente transferido entre usuários. Além disso, em dispositivos com vários perfis de usuário, qualquer um que receba mensagens SMS pode fazer login em uma conta usando o número de telefone do dispositivo.

Caso use o login com número de telefone no seu app, você precisa oferecê-lo junto com métodos de login mais seguros e informar aos usuários as implicações de segurança do uso desse tipo de login.

Ativar o login com número de telefone para o projeto do Firebase

Para fazer login de usuários por SMS, ative primeiro o método de login com número de telefone no projeto do Firebase:

  1. No Console do Firebase, abra a seção Autenticação.
  2. Na página Método de login, ative o método de login por Número de telefone.
  3. Na mesma página, adicione o domínio que hospedará o app se ele não estiver listado na seção Domínios de redirecionamento OAuth.

A cota de solicitação de login por número de telefone do Firebase é alta o suficiente, de modo que a maioria dos apps não é afetada. No entanto, se for necessário fazer login de um grande volume de usuários com autenticação por telefone, atualize o plano de preços. Consulte a página de preços.

Configurar o verificador reCAPTCHA

Antes de poder fazer login de usuários com os números de telefone deles, é preciso configurar o verificador reCAPTCHA do Firebase. O Firebase usa reCAPTCHA para evitar abusos, como ao assegurar que a solicitação de verificação por número de telefone provenha de um dos domínios permitidos do app.

Não é necessário configurar manualmente um cliente reCAPTCHA. Quando você usa o objeto RecaptchaVerifier do SDK do Firebase, a plataforma cria e processa de forma automática todas as chaves e secrets necessários.

O objeto RecaptchaVerifier é tem suporte a reCAPTCHA invisível, que geralmente verifica o usuário sem exigir nenhuma ação dele. Ele também tem suporte ao widget reCAPTCHA, que sempre exige a interação do usuário para ser concluído.

O reCAPTCHA renderizado pode ser localizado de acordo com a preferência do usuário. Para isso, atualize o código do idioma na instância do Auth antes de renderizar o reCAPTCHA. A mensagem SMS enviada ao usuário com o código de verificação vai usar a mesma localização mencionada acima.

API modular da Web

import { getAuth } from "firebase/auth";

const auth = getAuth();
auth.languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// auth.useDeviceLanguage();

API com namespace da Web

firebase.auth().languageCode = 'it';
// To apply the default browser preference instead of explicitly setting it.
// firebase.auth().useDeviceLanguage();

Usar reCAPTCHA invisível

Para usar um reCAPTCHA invisível, crie um objeto RecaptchaVerifier com o parâmetro size configurado como invisible, especificando o ID do botão que envia o formulário de login. Exemplo:

API modular da Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

API com namespace da Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('sign-in-button', {
  'size': 'invisible',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    onSignInSubmit();
  }
});

Usar o widget reCAPTCHA

Para usar o widget reCAPTCHA visível, crie um elemento na sua página para conter o widget e, em seguida, crie um objeto RecaptchaVerifier, especificando o ID do contêiner quando você fizer isso. Por exemplo:

API modular da Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {});

API com namespace da Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');

Opcional: especificar parâmetros do reCAPTCHA

Você também tem a opção de definir funções de retorno de chamada no objeto RecaptchaVerifier que são chamadas quando o usuário resolve o reCAPTCHA ou quando o reCAPTCHA expira antes que o usuário envie o formulário:

API modular da Web

import { getAuth, RecaptchaVerifier } from "firebase/auth";

const auth = getAuth();
window.recaptchaVerifier = new RecaptchaVerifier(auth, 'recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

API com namespace da Web

window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
  'size': 'normal',
  'callback': (response) => {
    // reCAPTCHA solved, allow signInWithPhoneNumber.
    // ...
  },
  'expired-callback': () => {
    // Response expired. Ask user to solve reCAPTCHA again.
    // ...
  }
});

Opcional: pré-renderizar o reCAPTCHA

Se você quiser pré-renderizar o reCAPTCHA antes de enviar uma solicitação de login, chame render:

API modular da Web

recaptchaVerifier.render().then((widgetId) => {
  window.recaptchaWidgetId = widgetId;
});

API com namespace da Web

recaptchaVerifier.render().then((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:

API modular da Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

API com namespace da Web

const recaptchaResponse = grecaptcha.getResponse(recaptchaWidgetId);

Enviar um código de verificação ao telefone do usuário

Para iniciar o login com número de telefone, apresente ao usuário uma interface que solicite o número dele e, em seguida, chame signInWithPhoneNumber para pedir que o Firebase envie um código de autenticação por SMS ao smartphone do usuário:

  1. Solicite o número de telefone do usuário.

    Os requisitos legais variam, mas como prática recomendada e para definir as expectativas dos usuários, informe a eles que, se fizerem login com telefone, poderão receber uma mensagem SMS para verificação. Além disso, poderão ser cobrados por esse serviço.

  2. Chame signInWithPhoneNumber e transmita a ele o número de telefone do usuário e o RecaptchaVerifier criado anteriormente.

    API modular da Web

    import { getAuth, signInWithPhoneNumber } from "firebase/auth";
    
    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    
    const auth = getAuth();
    signInWithPhoneNumber(auth, phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });

    API com namespace da Web

    const phoneNumber = getPhoneNumberFromUserInput();
    const appVerifier = window.recaptchaVerifier;
    firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
        .then((confirmationResult) => {
          // SMS sent. Prompt user to type the code from the message, then sign the
          // user in with confirmationResult.confirm(code).
          window.confirmationResult = confirmationResult;
          // ...
        }).catch((error) => {
          // Error; SMS not sent
          // ...
        });
    Se signInWithPhoneNumber resultar em um erro, redefina o reCAPTCHA para que o usuário possa tentar novamente:
    grecaptcha.reset(window.recaptchaWidgetId);
    
    // Or, if you haven't stored the widget ID:
    window.recaptchaVerifier.render().then(function(widgetId) {
      grecaptcha.reset(widgetId);
    });
    

O método signInWithPhoneNumber emite o teste reCAPTCHA para o usuário e, se ele for aprovado, o método vai solicitar que o Firebase Authentication envie uma mensagem SMS com um código de verificação para o smartphone do usuário.

Fazer login do usuário com o código de verificação

Depois que a chamada para signInWithPhoneNumber for bem-sucedida, solicite que o usuário digite o código de verificação que recebeu por SMS. Em seguida, faça o login do usuário transmitindo o código para o método confirm do objeto ConfirmationResult que foi transmitido para o gerenciador de atendimento do signInWithPhoneNumber, ou seja, o bloco then. Exemplo:

API modular da Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

API com namespace da Web

const code = getCodeFromUserInput();
confirmationResult.confirm(code).then((result) => {
  // User signed in successfully.
  const user = result.user;
  // ...
}).catch((error) => {
  // User couldn't sign in (bad verification code?)
  // ...
});

Se a chamada para confirm tiver sido bem-sucedida, o usuário iniciará a sessão com sucesso.

Conseguir o objeto AuthCredential intermediário

Se você precisa conseguir um objeto AuthCredential para a conta do usuário, passe o código de verificação do resultado de confirmação e o código de verificação para PhoneAuthProvider.credential em vez de chamar confirm:

var credential = firebase.auth.PhoneAuthProvider.credential(confirmationResult.verificationId, code);

Então, você pode fazer login do usuário com a credencial:

firebase.auth().signInWithCredential(credential);

Testar com números de telefone fictícios

É possível configurar números de telefone fictícios para desenvolvimento no Console do Firebase. Com isso, você tem estes benefícios:

  • A autenticação do número de telefone é feita sem consumir sua cota de uso.
  • A autenticação do número de telefone é feita sem enviar uma mensagem SMS real.
  • Testes consecutivos são executados com o mesmo número de telefone, sem que haja limitação. Isso minimiza o risco de rejeição durante o processo de revisão da App store, caso o revisor use o mesmo número de telefone para teste.
  • O teste em ambientes de desenvolvimento é feito prontamente e sem esforço extra, como a capacidade de desenvolver um simulador do iOS ou um emulador do Android sem o Google Play Services.
  • A criação de testes de integração é feita sem que haja bloqueio por verificações de segurança, que normalmente são aplicadas a números de telefone reais em um ambiente de produção.

Os números de telefone fictícios precisam atender a estes requisitos:

  1. Use números de telefone que sejam realmente fictícios e não existam. O Firebase Authentication não permite que você configure números de telefone existentes já usados por usuários reais como números de teste. Uma opção é usar números com prefixo 555 como números de telefone de teste dos EUA, por exemplo: +1 650-555-3434
  2. Os números de telefone precisam estar formatados corretamente para atender a restrições como o tamanho. Eles ainda passarão pela mesma validação dos números de usuários reais.
  3. Você pode adicionar até 10 números de telefone para desenvolvimento.
  4. Use números de telefone/códigos de teste difíceis de adivinhar e altere-os com frequência.

Criar números de telefone e códigos de verificação fictícios

  1. No Console do Firebase, abra a seção Autenticação.
  2. Na guia Método de login, ative o provedor de telefonia, se ainda não fez isso.
  3. Abra o menu suspenso Números de telefone para testes.
  4. Informe o número de telefone que você quer testar, por exemplo: +1 650-555-3434.
  5. Informe o código de verificação de seis dígitos para esse número específico, por exemplo: 654321.
  6. Adicione o número. Se precisar, exclua o número de telefone e o código. Basta passar o cursor sobre a linha correspondente e clicar no ícone da lixeira.

Teste manual

Você pode começar a usar um número de telefone fictício diretamente no seu aplicativo. Dessa maneira, você pode executar testes manuais durante as etapas de desenvolvimento sem problemas de cotas ou limitações. Também é possível testar diretamente, a partir de um simulador do iOS ou emulador do Android, sem a instalação do Google Play Services.

Quando você fornece o número de telefone fictício e envia o código de verificação, nenhum SMS real é enviado. Em vez disso, é necessário informar o código de verificação configurado anteriormente para concluir o login.

Quando o login é concluído, um usuário do Firebase é criado com aquele número de telefone. Este usuário tem o mesmo comportamento e propriedades de um usuário com um número de telefone real e pode acessar o Realtime Database/Cloud Firestore e outros serviços da mesma forma. O token de ID gerado durante esse processo tem a mesma assinatura de um usuário com um número de telefone real.

Outra opção é definir um papel de teste por meio de declarações personalizadas nesses usuários para diferenciá-los como usuários falsos, se você quiser restringir ainda mais o acesso.

Teste de integração

Além do teste manual, o Firebase Authentication conta com APIs para ajudar a escrever testes de integração para o teste de autenticação por telefone. Essas APIs desativam a verificação de apps removendo o requisito reCAPTCHA na Web e em notificações push silenciosas no iOS. Isso possibilita o teste de automação nesses fluxos e facilita a implementação. Além disso, fica mais fácil testar os fluxos de verificação instantânea no Android.

Na Web, defina appVerificationDisabledForTesting como true antes de renderizar o firebase.auth.RecaptchaVerifier. Isso resolve o reCAPTCHA automaticamente para que você possa passar o número de telefone sem precisar resolvê-lo de forma manual. Observe que, mesmo com o reCAPTCHA desativado, o login não é concluído se for usado um número de telefone não fictício. Só é possível usar números de telefone fictícios com essa API.

// Turn off phone auth app verification.
firebase.auth().settings.appVerificationDisabledForTesting = true;

var phoneNumber = "+16505554567";
var testVerificationCode = "123456";

// This will render a fake reCAPTCHA as appVerificationDisabledForTesting is true.
// This will resolve after rendering without app verification.
var appVerifier = new firebase.auth.RecaptchaVerifier('recaptcha-container');
// signInWithPhoneNumber will call appVerifier.verify() which will resolve with a fake
// reCAPTCHA response.
firebase.auth().signInWithPhoneNumber(phoneNumber, appVerifier)
    .then(function (confirmationResult) {
      // confirmationResult can resolve with the fictional testVerificationCode above.
      return confirmationResult.confirm(testVerificationCode)
    }).catch(function (error) {
      // Error; SMS not sent
      // ...
    });

O comportamento dos verificadores de aplicativo reCAPTCHA simulados visíveis e invisíveis varia quando a verificação de apps está desativada:

  • reCAPTCHA visível: quando o reCAPTCHA visível é renderizado usando appVerifier.render(), ele é resolvido automaticamente após um atraso de uma fração de segundo. Isso equivale a um usuário que clica no reCAPTCHA imediatamente após a renderização. A resposta reCAPTCHA expira após algum tempo e é resolvida automaticamente outra vez.
  • reCAPTCHA invisível: o reCAPTCHA invisível não é resolvido automaticamente na renderização, mas sim na chamada appVerifier.verify() ou quando a âncora de botão do reCAPTCHA é clicada após uma fração de segundo. Da mesma forma, a resposta expira após algum tempo e só é resolvida automaticamente após a chamada de appVerifier.verify() ou quando a âncora de botão do reCAPTCHA é clicada novamente.

Sempre que um reCAPTCHA simulado é resolvido, a função de callback correspondente é acionada com a resposta falsa conforme esperado. Se um callback de expiração também for especificado, ele será acionado quando a resposta expirar.

Próximas etapas

Depois que um usuário faz login pela primeira vez, uma nova conta de usuário é criada e vinculada às credenciais, que podem ser o número do telefone, o nome de usuário e a senha ou as informações do provedor de autenticação. Essa nova conta é armazenada como parte do projeto do Firebase e pode ser usada para identificar um usuário em todos os apps do projeto, seja qual for o método de login utilizado.

  • Nos apps, a maneira recomendada de saber o status de autenticação do seu usuário é definindo um observador no objeto Auth. É possível, então, receber as informações básicas de perfil do usuário do objeto User. Consulte Gerenciar usuários.

  • Nas Regras de segurança do Firebase Realtime Database e do Cloud Storage, é possível receber o ID exclusivo do usuário conectado da variável auth e usar esse ID para controlar quais dados uma pessoa pode acessar.

Os usuários podem fazer login no app usando vários provedores de autenticação. Basta vincular as credenciais desses provedores a uma conta de usuário.

Para desconectar um usuário, chame signOut:

API modular da Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

API com namespace da Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});