Agregue autenticación multifactor TOTP a su aplicación iOS

Si actualizó a Firebase Authentication con Identity Platform, puede agregar autenticación multifactor (MFA) con contraseña de un solo uso basada en tiempo (TOTP) a su aplicación.

Firebase Authentication con Identity Platform le permite usar un TOTP como factor adicional para MFA. Cuando habilita esta función, los usuarios que intentan iniciar sesión en su aplicación ven una solicitud de TOTP. Para generarlo deben utilizar una aplicación de autenticación capaz de generar códigos TOTP válidos, como Google Authenticator .

Antes de que empieces

  1. Habilite al menos un proveedor que admita MFA. Tenga en cuenta que todos los proveedores , excepto los siguientes, admiten MFA:

    • autenticación telefónica
    • autenticación anónima
    • Tokens de autenticación personalizados
    • Centro de juegos de Apple
  2. Asegúrese de que su aplicación verifique las direcciones de correo electrónico de los usuarios. MFA requiere verificación por correo electrónico. Esto evita que actores malintencionados se registren en un servicio con una dirección de correo electrónico que no les pertenece y luego bloqueen al propietario real de la dirección de correo electrónico agregando un segundo factor.

  3. Si aún no lo has hecho, instala el SDK de Firebase Apple .

    TOTP MFA solo es compatible con la versión v10.12.0 y superior del SDK de Apple , y solo en iOS.

Habilitar TOTP MFA

Para habilitar TOTP como segundo factor, utilice el SDK de administración o llame al punto final REST de configuración del proyecto.

Para utilizar el SDK de administrador, haga lo siguiente:

  1. Si aún no lo has hecho, instala el SDK de Firebase Admin Node.js.

    TOTP MFA solo se admite en las versiones 11.6.0 y superiores del SDK de Firebase Admin Node.js.

  2. Ejecute lo siguiente:

    import { getAuth } from 'firebase-admin/auth';
    
    getAuth().projectConfigManager().updateProjectConfig(
    {
          multiFactorConfig: {
              providerConfigs: [{
                  state: "ENABLED",
                  totpProviderConfig: {
                      adjacentIntervals: {
                          NUM_ADJ_INTERVALS
                      },
                  }
              }]
          }
    })
    

    Reemplace lo siguiente:

    • NUM_ADJ_INTERVALS : el número de intervalos de ventana de tiempo adyacentes desde los cuales aceptar TOTP, de cero a diez. El valor predeterminado es cinco.

      Los TOTP funcionan garantizando que cuando dos partes (el probador y el validador) generen OTP dentro del mismo período de tiempo (normalmente de 30 segundos de duración), generen la misma contraseña. Sin embargo, para adaptarse a la variación del reloj entre las partes y el tiempo de respuesta humana, puede configurar el servicio TOTP para que también acepte TOTP de ventanas adyacentes.

Para habilitar TOTP MFA usando la API REST, ejecute lo siguiente:

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"
            }
          }]
       }
    }'

Reemplace lo siguiente:

  • PROJECT_ID : el ID del proyecto.
  • NUM_ADJ_INTERVALS : el número de intervalos de ventana de tiempo, de cero a diez. El valor predeterminado es cinco.

    Los TOTP funcionan garantizando que cuando dos partes (el probador y el validador) generen OTP dentro del mismo período de tiempo (normalmente de 30 segundos de duración), generen la misma contraseña. Sin embargo, para adaptarse a la variación del reloj entre las partes y el tiempo de respuesta humana, puede configurar el servicio TOTP para que también acepte TOTP de ventanas adyacentes.

Elija un patrón de inscripción

Puede elegir si su aplicación requiere autenticación multifactor y cómo y cuándo inscribir a sus usuarios. Algunos patrones comunes incluyen los siguientes:

  • Inscriba el segundo factor del usuario como parte del registro. Utilice este método si su aplicación requiere autenticación multifactor para todos los usuarios.

  • Ofrezca una opción que se pueda omitir para inscribir un segundo factor durante el registro. Si desea fomentar, pero no exigir, la autenticación multifactor en su aplicación, puede utilizar este enfoque.

  • Brinde la posibilidad de agregar un segundo factor desde la cuenta del usuario o la página de administración de perfil, en lugar de la pantalla de registro. Esto minimiza la fricción durante el proceso de registro y al mismo tiempo hace que la autenticación multifactor esté disponible para los usuarios sensibles a la seguridad.

  • Requerir agregar un segundo factor de manera incremental cuando el usuario desee acceder a funciones con mayores requisitos de seguridad.

Inscribir usuarios en TOTP MFA

Después de habilitar TOTP MFA como segundo factor para su aplicación, implemente la lógica del lado del cliente para inscribir usuarios en TOTP MFA:

  1. Vuelva a autenticar al usuario.

  2. Genere un secreto TOTP para el usuario 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. Muestre el secreto al usuario y solicítele que lo ingrese en su aplicación de autenticación:

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

    Además de mostrar la clave secreta, puede intentar agregarla automáticamente a la aplicación de autenticación predeterminada del dispositivo. Para hacerlo, genere un URI de clave compatible con Google Authenticator y páselo a openInOTPApp(withQRCodeURL:) :

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

    Después de que el usuario agregue su secreto a su aplicación de autenticación, esta comenzará a generar TOTP.

  4. Solicite al usuario que escriba el TOTP que muestra su aplicación de autenticación y lo utilice para finalizar la inscripción en 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.
    }
    

Iniciar sesión usuarios con un segundo factor

Para iniciar sesión de usuarios con TOTP MFA, utilice el siguiente código:

  1. Llame a uno de los métodos signIn(with...:) como lo haría si no estuviera usando MFA (por ejemplo, signIn(withEmail:password:) ). Si el método arroja un error con el código secondFactorRequired , inicie el flujo MFA de su aplicación.

    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. El flujo MFA de su aplicación primero debe pedirle al usuario que elija el segundo factor que desea usar. Puede obtener una lista de segundos factores admitidos examinando la propiedad de hints de una instancia MultiFactorResolver :

    let mfaKey = AuthErrorUserInfoMultiFactorResolverKey
    guard let resolver = error.userInfo[mfaKey] as? MultiFactorResolver else { return }
    let enrolledFactors = resolver.hints.map(\.displayName)
    
  3. Si el usuario elige usar TOTP, solicítele que escriba el TOTP que se muestra en su aplicación de autenticación y utilícelo para iniciar sesión:

    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
    }
    

Darse de baja de TOTP MFA

Esta sección describe cómo manejar la cancelación de la inscripción de un usuario en TOTP MFA.

Si un usuario se ha registrado en varias opciones de MFA y se da de baja de la opción habilitada más recientemente, recibe un auth/user-token-expired y se cierra su sesión. El usuario debe iniciar sesión nuevamente y verificar sus credenciales existentes (por ejemplo, una dirección de correo electrónico y una contraseña).

Para cancelar la inscripción del usuario, controlar el error y activar la reautenticación, utilice el siguiente 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.
}

Que sigue