Agregue autenticación multifactor TOTP a su aplicación de Android

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 para Android .

    TOTP MFA solo es compatible con la versión del SDK de Android v22.1.0 y superior.

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.
    Firebase.auth.currentUser.multiFactor.session
        .addOnSuccessListener { multiFactorSession ->
            TotpMultiFactorGenerator.generateSecret(multiFactorSession)
                .addOnSuccessListener { totpSecret ->
                    // 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:
    val 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() :

    val qrCodeUri = totpSecret.generateQrCodeUrl(
        currentUser.email ?: "default account",
        "Your App Name")
    totpSecret.openInOtpApp(qrCodeUri)
    

    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.
    val verificationCode = // Code from user input.
    
    // Finalize the enrollment.
    val multiFactorAssertion = TotpMultiFactorGenerator
        .getAssertionForEnrollment(totpSecret, verificationCode)
    Firebase.auth.currentUser.multiFactor.enroll(multiFactorAssertion, "TOTP")
        .addOnSuccessListener {
            // Enrollment complete.
        }
    

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 signInWith - como lo haría si no estuviera usando MFA. (Por ejemplo, signInWithEmailAndPassword() ). Si el método genera una FirebaseAuthMultiFactorException , inicia el flujo de MFA de tu aplicación.

    Firebase.auth.signInWithEmailAndPassword(email, password)
        .addOnSuccessListener { result ->
            // 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.)
    
            // ...
        }
        .addOnFailureListener { exception ->
            when (exception) {
                is FirebaseAuthMultiFactorException -> {
                    // Initiate your second factor sign-in flow. (See next step.)
                    // ...
                }
            }
        }
    
  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 :

    val enrolledFactors = exception.resolver.hints.map { it.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:

    when (exception.resolver.hints[selectedIndex].factorId) {
        TotpMultiFactorGenerator.FACTOR_ID -> {
            val otpFromAuthenticator = // OTP typed by the user.
            val assertion = TotpMultiFactorGenerator.getAssertionForSignIn(
                exception.resolver.hints[selectedIndex].uid,
                otpFromAuthenticator
            )
            exception.resolver.resolveSignIn(assertion)
                .addOnSuccessListener { result ->
                    // Successfully signed in!
                }
                .addOnFailureListener { resolveError ->
                    // Invalid or expired OTP.
                }
        }
        PhoneMultiFactorGenerator.FACTOR_ID -> {
            // Handle SMS second factor.
        }
    }
    

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:

Firebase.auth.currentUser.multiFactor.unenroll(mfaEnrollmentId)
    .addOnSuccessListener {
        // Second factor unenrolled.
    }
    .addOnFailureListener { exception ->
        when (exception) {
            is FirebaseAuthInvalidUserException -> {
                // Second factor unenrolled. 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.
                val credential = EmailAuthProvider.getCredential(email, password)
                currentUser.reauthenticate(credential)
                    .addOnSuccessListener { 
                        // Success!
                    }
                    .addOnFailureListener { 
                        // Bad email address and password combination.
                    }
            }
        }
    }

Que sigue