Como adicionar a autenticação multifator TOTP ao seu app da Web

Se você fez upgrade para o Firebase Authentication com o Identity Platform, pode adicionar ao seu app a autenticação multifator (MFA) baseada em tempo único (TOTP).

O Firebase Authentication com o Identity Platform permite usar um TOTP como fator adicional para a autenticação multifator (MFA). Quando você ativa esse recurso, os usuários que tentam fazer login no app visualizam uma solicitação de um TOTP. Para gerá-lo, é necessário usar um app autenticador capaz de gerar códigos TOTP válidos, como o Google Authenticator.

Antes de começar

  1. Ative pelo menos um provedor compatível com a autenticação multifator (MFA). Todos os provedores, exceto os seguintes MFA de suporte:

    • Autenticação por telefone
    • Autenticação anônima
    • Tokens de autenticação personalizados
    • Apple Game Center
  2. Verifique se o app verifica os endereços de e-mail dos usuários. A autenticação multifator (MFA) requer verificação de e-mail. Isso impede que agentes mal-intencionados se registrem em um serviço com um endereço de e-mail que não tenham e bloqueiem o proprietário real do endereço de e-mail adicionando um segundo fator.

  3. Instale o SDK do Firebase para JavaScript, caso ainda não tenha feito isso.

    A MFA TOTP é compatível apenas com o SDK da Web modular v9.19.1 e versões mais recentes.

  4. Instale o SDK Admin do Firebase, caso ainda não tenha feito isso.

    A TOFA MFA só é compatível com as versões 11.6.0 e posteriores do SDK Admin do Firebase.

Ativar MFA TOTP

Para ativar o TOTP como segundo fator, use o SDK Admin ou chame o endpoint REST da configuração do projeto.

Para usar o SDK Admin, execute o seguinte:

import { getAuth } from 'firebase-admin/auth';

getAuth().projectConfigManager().updateProjectConfig(
{
      multiFactorConfig: {
          providerConfigs: [{
              state: "ENABLED",
              totpProviderConfig: {
                  adjacentIntervals: {
                      NUM_ADJ_INTERVALS
                  },
              }
          }]
      }
})

Substitua:

  • NUM_ADJ_INTERVALS: o número de intervalos de janela de tempo, de zero a dez. O padrão é cinco.

Para ativar a MTP TOTP usando a API REST, execute o seguinte:

curl -X PATCH "https://identitytoolkit.googleapis.com/admin/v2/projects/PROJECT_ID/config?updateMask=mfa" \
    -H "Authorization: Bearer $(gcloud auth print-access-token)" \
    -H "Content-Type: application/json" \
    -H "X-Goog-User-Project: PROJECT_ID" \
    -d \
    '{
        "mfa": {
          "providerConfigs": [{
            "state": "ENABLED",
            "totpProviderConfig": {
              "adjacentIntervals": "NUM_ADJ_INTERVALS"
            }
          }]
       }
    }'

Substitua:

  • PROJECT_ID: o ID do projeto.
  • NUM_ADJ_INTERVALS: o número de intervalos de janela de tempo, de zero a dez. O padrão é cinco.

Escolha 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 pulável para registrar um segundo fator durante o processo. Se você quiser incentivar, mas não exigir, a autenticação multifator no seu app, use 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.

Inscrever usuários na TOTP MFA

Depois de ativar a TOFA MFA como o segundo fator do app, implemente a lógica do cliente para registrar usuários na TOTP MFA:

  1. Importe as classes e funções de MFA necessárias:

    import {
      multiFactor,
      TotpMultiFactorGenerator,
      TotpSecret,
      getAuth,
    } from "firebase/auth";
    
  2. Reautentique o usuário.

  3. Gere um segredo TOTP para o usuário autenticado:

    // Generate a TOTP secret.
    const multiFactorSession = await multiFactor(currentUser).getSession();
    const totpSecret = await TotpMultiFactorGenerator.generateSecret(
      multiFactorSession
    );
    
  4. Mostre a chave secreta ao usuário e solicite que ele a insira no app autenticador.

    Com muitos apps de autenticador, os usuários podem adicionar rapidamente novas chaves secretas de TOTP por meio da leitura de um código QR que representa um URI de chave compatível com o Google Authenticator. Para gerar um código QR para esse fim, gere o URI com generateQrCodeUrl() e codifique-o usando a biblioteca de código QR de sua escolha. Exemplo:

    const totpUri = totpSecret.generateQrCodeUrl(
        currentUser.email,
        "Your App's Name"
    );
    await QRExampleLib.toCanvas(totpUri, qrElement);
    

    Independentemente de você exibir um código QR, sempre exiba a chave secreta para dar suporte a apps autenticadores que não conseguem ler códigos QR:

    // Also display this key:
    const secret = totpSecret.secretKey;
    

    Depois que o usuário adiciona a chave secreta ao app autenticador, ele começa a gerar TOTPs.

  5. Peça ao usuário para digitar o TOTP exibido no app autenticador e usá-lo para finalizar o registro da MFA:

    // Ask the user for a verification code from the authenticator app.
    const verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    const multiFactorAssertion = TotpMultiFactorGenerator.assertionForEnrollment(
      totpSecret,
      verificationCode
    );
    await multiFactor(currentUser).enroll(multiFactorAssertion, mfaDisplayName);
    

Fazer login de usuários com um segundo fator

Para fazer login de usuários com a MFA TOTP, use o seguinte código:

  1. Importe as classes e funções de MFA necessárias:

    import {
        getAuth,
        getMultiFactorResolver,
        TotpMultiFactorGenerator,
    } from "firebase/auth";
    
  2. Chame um dos métodos signInWith como faria se não estivesse usando a MFA. Por exemplo, signInWithEmailAndPassword(). Se o método gerar um erro auth/multi-factor-auth-required, inicie o fluxo de MFA do app.

    try {
        const userCredential = await signInWithEmailAndPassword(
            getAuth(),
            email,
            password
        );
        // If the user is not enrolled with a second factor and provided valid
        // credentials, sign-in succeeds.
    
        // (If your app requires MFA, this could be considered an error
        // condition, which you would resolve by forcing the user to enroll a
        // second factor.)
    
        // ...
    } catch (error) {
        switch (error.code) {
            case "auth/multi-factor-auth-required":
                // Initiate your second factor sign-in flow. (See next step.)
                // ...
                break;
            case ...:  // Handle other errors, such as wrong passwords.
                break;
        }
    }
    
  3. Primeiro, o fluxo de MFA do app solicitará que o usuário escolha o segundo fator que ele quer usar. Para conseguir uma lista de fatores secundários compatíveis, examine a propriedade hints de uma instância MultiFactorResolver:

    const mfaResolver = getMultiFactorResolver(getAuth(), error);
    const enrolledFactors = mfaResolver.hints.map(info => info.displayName);
    
  4. Se o usuário optar por usar o TOTP, solicite que ele digite o TOTP exibido no app autenticador e o use para fazer login:

    switch (mfaResolver.hints[selectedIndex].factorId) {
        case TotpMultiFactorGenerator.FACTOR_ID:
            const otpFromAuthenticator = // OTP typed by the user.
            const multiFactorAssertion =
                TotpMultiFactorGenerator.assertionForSignIn(
                    mfaResolver.hints[selectedIndex].uid,
                    otpFromAuthenticator
                );
            try {
                const userCredential = await mfaResolver.resolveSignIn(
                    multiFactorAssertion
                );
                // Successfully signed in!
            } catch (error) {
                // Invalid or expired OTP.
            }
            break;
        case PhoneMultiFactorGenerator.FACTOR_ID:
            // Handle SMS second factor.
            break;
        default:
            // Unsupported second factor?
            break;
    }
    

Cancelar inscrição na TOTP MFA

Esta seção descreve como lidar com um usuário que cancela a inscrição na TOFA MFA.

Se um usuário se inscrever em várias opções de MFA e se cancelar a inscrição na opção ativada mais recentemente, ele receberá uma auth/user-token-expired e será desconectado. O usuário precisará fazer login novamente e verificar as credenciais existentes, por exemplo, um endereço de e-mail e uma senha.

Para cancelar a inscrição do usuário, lidar com o erro e acionar a reautenticação, use o seguinte código:

import {
    EmailAuthProvider,
    TotpMultiFactorGenerator,
    getAuth,
    multiFactor,
    reauthenticateWithCredential,
} from "firebase/auth";

try {
    // Unenroll from TOTP MFA.
    await multiFactor(currentUser).unenroll(TotpMultiFactorGenerator.FACTOR_ID);
} catch  (error) {
    if (error.code === 'auth/user-token-expired') {
        // If the user was signed out, re-authenticate them.

        // For example, if they signed in with a password, prompt them to
        // provide it again, then call `reauthenticateWithCredential()` as shown
        // below.

        const credential = EmailAuthProvider.credential(email, password);
        await reauthenticateWithCredential(
            currentUser,
            credential
        );
    }
}

A seguir