Adicionar a autenticação multifator do TOTP ao seu app iOS

Se você fez upgrade para o Firebase Authentication with Identity Platform, poderá adicionar ao seu app a autenticação multifator (MFA) com uma senha única baseada em tempo (TOTP).

Firebase Authentication with Identity Platform permite que você use uma TOTP como um fator adicional para a MFA. Quando você ativa esse recurso, os usuários que tentam fazer login no app visualizam uma solicitação de um TOTP. Para gerá-la, é 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 Apple, caso ainda não tenha feito isso.

    O TOTP MFA é compatível apenas com o SDK da Apple versão v10.12.0 e posteriores e apenas no iOS.

Ativar MFA TOTP

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

Para usar o Admin SDK, faça o seguinte:

  1. Instale o SDK Admin para Node.js do Firebase, caso ainda não tenha feito isso.

    O TOTP MFA só é compatível com o SDK Admin para Node.js do Firebase versão 11.6.0 e mais recentes.

  2. Execute o comando a seguir:

    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 adjacentes a partir dos quais aceitar TOTPs, de zero a dez. O padrão é cinco.

      Os TOTPs garantem que, quando duas partes (o responsável e o validador) gerarem OTPs na mesma janela de tempo (normalmente 30 segundos), elas gerem a mesma senha. No entanto, para acomodar o deslocamento do relógio entre as partes e o tempo de resposta humano, você pode configurar o serviço TOTP para aceitar também TOTPs de janelas adjacentes.

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.

    Os TOTPs garantem que, quando duas partes (o responsável e o validador) gerarem OTPs na mesma janela de tempo (normalmente 30 segundos), elas gerem a mesma senha. No entanto, para acomodar o deslocamento do relógio entre as partes e o tempo de resposta humano, você pode configurar o serviço TOTP para aceitar também TOTPs de janelas adjacentes.

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 que pode ser ignorada 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. Reautentique o usuário.

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

    // Generate a TOTP secret.
    guard let mfaSession = try? await currentUser.multiFactor.session() else { return }
    guard let totpSecret = try? await TOTPMultiFactorGenerator.generateSecret(with: mfaSession) else { return }
    
    // Display the secret to the user and prompt them to enter it into their
    // authenticator app. (See the next step.)
    
  3. Mostre a chave secreta ao usuário e solicite que ele a insira no app autenticador:

    // Display this key:
    let secret = totpSecret.sharedSecretKey()
    

    Além de exibir a chave secreta, você pode tentar adicioná-la automaticamente ao app autenticador padrão do dispositivo. Para fazer isso, gere um URI de chave compatível com o Google Authenticator e o transmita para openInOTPApp(withQRCodeURL:):

    let otpAuthUri = totpSecret.generateQRCodeURL(
        withAccountName: currentUser.email ?? "default account",
        issuer: "Your App Name")
    totpSecret.openInOTPApp(withQRCodeURL: otpAuthUri)
    

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

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

    // Ask the user for a verification code from the authenticator app.
    let verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    let multiFactorAssertion = TOTPMultiFactorGenerator.assertionForEnrollment(
        with: totpSecret,
        oneTimePassword: verificationCode)
    do {
        try await currentUser.multiFactor.enroll(
            with: multiFactorAssertion,
            displayName: "TOTP")
    } catch {
        // Wrong or expired OTP. Re-prompt the user.
    }
    

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. Chame um dos métodos signIn(with...:) como você faria se não estivesse usando a MFA (por exemplo, signIn(withEmail:password:)). Se o método gerar um erro com o código secondFactorRequired, inicie o fluxo de MFA do app.

    do {
        let authResult = try await Auth.auth().signIn(withEmail: email, password: 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 let error as AuthErrorCode where error.code == .secondFactorRequired {
        // Initiate your second factor sign-in flow. (See next step.)
        // ...
    } catch {
        // Other auth error.
        throw error
    }
    
  2. 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:

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. 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:

    let multiFactorInfo = resolver.hints[selectedIndex]
    switch multiFactorInfo.factorID {
    case TOTPMultiFactorID:
        let otpFromAuthenticator = // OTP typed by the user.
        let assertion = TOTPMultiFactorGenerator.assertionForSignIn(
            withEnrollmentID: multiFactorInfo.uid,
            oneTimePassword: otpFromAuthenticator)
        do {
            let authResult = try await resolver.resolveSignIn(with: assertion)
        } catch {
            // Wrong or expired OTP. Re-prompt the user.
        }
    default:
        return
    }
    

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:

guard let currentUser = Auth.auth().currentUser else { return }

// Prompt the user to select a factor to unenroll, from this array:
currentUser.multiFactor.enrolledFactors

// ...

// Unenroll the second factor.
let multiFactorInfo = currentUser.multiFactor.enrolledFactors[selectedIndex]
do {
    try await currentUser.multiFactor.unenroll(with: multiFactorInfo)
} catch let error as AuthErrorCode where error.code == .invalidUserToken {
    // Second factor unenrolled, but the user was signed out. Re-authenticate
    // them.
}

A seguir