Ir a la consola

Autentica con Firebase en Android mediante un número de teléfono

Puedes usar Firebase Authentication para hacer que un usuario acceda mediante el envío de un mensaje SMS a su teléfono. El usuario accede con un código único que se incluye en el mensaje SMS.

La forma más fácil de agregar un acceso con número de teléfono a la app es usar FirebaseUI, que incluye un widget de acceso directo que implementa flujos de acceso con número de teléfono, además de acceso federado y con contraseña. En este documento, se describe cómo implementar un flujo de acceso con el número de teléfono mediante el uso del SDK de Firebase.

Antes de comenzar

  1. Si aún no lo has hecho, agrega Firebase a tu proyecto de Android.
  2. Agrega la dependencia para la biblioteca de Android de Firebase Authentication al archivo Gradle (a nivel de la app) de tu módulo (generalmente app/build.gradle):
    implementation 'com.google.firebase:firebase-auth:16.2.1'
  3. Si aún no has conectado la app al proyecto de Firebase, puedes hacerlo desde Firebase console.
  4. Configura el hash SHA-1 de la app en Firebase console, si aún no lo hiciste. Consulta cómo autenticar tu cliente para ver detalles sobre cómo obtener el hash SHA-1 de la app.

Además, ten en cuenta que para el acceso con número de teléfono se necesita un dispositivo físico; este proceso no funciona en un simulador.

Preocupaciones de seguridad

Si bien la autenticación con solo un número de teléfono es conveniente, es menos segura que otros métodos disponibles, ya que la posesión de un número de teléfono se puede transferir con facilidad entre usuarios. Además, en los dispositivos con varios perfiles de usuario, cualquier usuario que reciba mensajes SMS puede acceder a una cuenta con el número de teléfono del dispositivo.

Si usas el acceso con número de teléfono en la app, deberías ofrecerlo junto con métodos de acceso más seguros, además de informar a los usuarios acerca de las desventajas de usar el acceso con número de teléfono.

Habilita el acceso con número de teléfono para el proyecto de Firebase

Para que los usuarios accedan a través de SMS, primero debes habilitar el método de acceso con el número de teléfono para el proyecto de Firebase:

  1. En Firebase console, abre la sección Authentication.
  2. En la página Método de acceso, habilita el método de acceso Número de teléfono.

La cuota de solicitudes de acceso con el número de teléfono de Firebase es lo suficientemente alta para que la mayoría de las apps no tengan problemas. Sin embargo, si necesitas permitir el acceso de un gran volumen de usuarios con autenticación por teléfono, es posible que debas actualizar tu plan de precios. Consulta la página de precios.

Envía un código de verificación al teléfono del usuario

Para iniciar el acceso con número de teléfono, muéstrale al usuario una interfaz que le pida ingresar su número de teléfono. Los requisitos legales varían, pero es recomendable establecer las expectativas de los usuarios informándoles que, si usan el acceso con el teléfono, es posible que reciban un mensaje SMS para la verificación y que se apliquen las tarifas estándar.

A continuación, pasa el número de teléfono al método PhoneAuthProvider.verifyPhoneNumber para solicitar que Firebase verifique el número de teléfono del usuario. Por ejemplo:

Java
Android

PhoneAuthProvider.getInstance().verifyPhoneNumber(
        phoneNumber,        // Phone number to verify
        60,                 // Timeout duration
        TimeUnit.SECONDS,   // Unit of timeout
        this,               // Activity (for callback binding)
        mCallbacks);        // OnVerificationStateChangedCallbacks

Kotlin
Android

PhoneAuthProvider.getInstance().verifyPhoneNumber(
        phoneNumber,      // Phone number to verify
        60,               // Timeout duration
        TimeUnit.SECONDS, // Unit of timeout
        this,             // Activity (for callback binding)
        callbacks) // OnVerificationStateChangedCallbacks

El método verifyPhoneNumber es reentrante, es decir, si lo llamas varias veces, como en un método de actividad onStart, verifyPhoneNumber no enviará un segundo SMS, a menos que se agote el tiempo de espera de la solicitud original.

Puedes usar este comportamiento para reanudar el proceso de acceso con número de teléfono en caso de que tu app se cierre antes de que el usuario pueda acceder a ella (por ejemplo, cuando el usuario use su app de SMS). Después de llamar a verifyPhoneNumber, configura una marca para informar que la verificación está en curso. Luego, guárdala en el método onSaveInstanceState de tu actividad y restáurala en onRestoreInstanceState. Por último, comprueba si la verificación ya está en curso en el método onStart de tu actividad. Si es así, vuelve a llamar a verifyPhoneNumber. Asegúrate de borrar la marca cuando la verificación finalice o no se realice correctamente (consulta las devoluciones de llamada de verificación).

A fin de manejar fácilmente la rotación de pantalla y otros casos de reinicio de la actividad, pásala al método verifyPhoneNumber. Las devoluciones de llamada se desvincularán automáticamente cuando se detenga la actividad, a fin de que puedas escribir el código de transición de la IU con libertad en los métodos de devolución de llamada.

El mensaje SMS que envía Firebase también puede localizarse si especificas el idioma de autenticación a través del método setLanguageCode en tu instancia de Auth.

Java
Android

auth.setLanguageCode("fr");
// To apply the default app language instead of explicitly setting it.
// auth.useAppLanguage();

Kotlin
Android

auth.setLanguageCode("fr")
// To apply the default app language instead of explicitly setting it.
// auth.useAppLanguage()

Cuando llames a PhoneAuthProvider.verifyPhoneNumber, también deberás proporcionar una instancia de OnVerificationStateChangedCallbacks que contenga implementaciones de las funciones de la devolución de llamada que trabajen con los resultados de la solicitud. Por ejemplo:

Java
Android

mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    @Override
    public void onVerificationCompleted(PhoneAuthCredential credential) {
        // This callback will be invoked in two situations:
        // 1 - Instant verification. In some cases the phone number can be instantly
        //     verified without needing to send or enter a verification code.
        // 2 - Auto-retrieval. On some devices Google Play services can automatically
        //     detect the incoming verification SMS and perform verification without
        //     user action.
        Log.d(TAG, "onVerificationCompleted:" + credential);

        signInWithPhoneAuthCredential(credential);
    }

    @Override
    public void onVerificationFailed(FirebaseException e) {
        // This callback is invoked in an invalid request for verification is made,
        // for instance if the the phone number format is not valid.
        Log.w(TAG, "onVerificationFailed", e);

        if (e instanceof FirebaseAuthInvalidCredentialsException) {
            // Invalid request
            // ...
        } else if (e instanceof FirebaseTooManyRequestsException) {
            // The SMS quota for the project has been exceeded
            // ...
        }

        // Show a message and update the UI
        // ...
    }

    @Override
    public void onCodeSent(String verificationId,
                           PhoneAuthProvider.ForceResendingToken token) {
        // The SMS verification code has been sent to the provided phone number, we
        // now need to ask the user to enter the code and then construct a credential
        // by combining the code with a verification ID.
        Log.d(TAG, "onCodeSent:" + verificationId);

        // Save verification ID and resending token so we can use them later
        mVerificationId = verificationId;
        mResendToken = token;

        // ...
    }
};

Kotlin
Android

callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    override fun onVerificationCompleted(credential: PhoneAuthCredential) {
        // This callback will be invoked in two situations:
        // 1 - Instant verification. In some cases the phone number can be instantly
        //     verified without needing to send or enter a verification code.
        // 2 - Auto-retrieval. On some devices Google Play services can automatically
        //     detect the incoming verification SMS and perform verification without
        //     user action.
        Log.d(TAG, "onVerificationCompleted:$credential")

        signInWithPhoneAuthCredential(credential)
    }

    override fun onVerificationFailed(e: FirebaseException) {
        // This callback is invoked in an invalid request for verification is made,
        // for instance if the the phone number format is not valid.
        Log.w(TAG, "onVerificationFailed", e)

        if (e is FirebaseAuthInvalidCredentialsException) {
            // Invalid request
            // ...
        } else if (e is FirebaseTooManyRequestsException) {
            // The SMS quota for the project has been exceeded
            // ...
        }

        // Show a message and update the UI
        // ...
    }

    override fun onCodeSent(
        verificationId: String?,
        token: PhoneAuthProvider.ForceResendingToken
    ) {
        // The SMS verification code has been sent to the provided phone number, we
        // now need to ask the user to enter the code and then construct a credential
        // by combining the code with a verification ID.
        Log.d(TAG, "onCodeSent:" + verificationId!!)

        // Save verification ID and resending token so we can use them later
        storedVerificationId = verificationId
        resendToken = token

        // ...
    }
}

Devoluciones de llamada de verificación

En la mayoría de las apps, se implementan las devoluciones de llamada onVerificationCompleted, onVerificationFailed y onCodeSent. Es posible que también puedas implementar onCodeAutoRetrievalTimeOut en función de los requisitos de tu app.

onVerificationCompleted(PhoneAuthCredential)

Este método se llama en dos situaciones:

  • Verificación instantánea: En algunos casos, el número de teléfono se puede verificar de manera instantánea, sin necesidad de enviar o ingresar un código de verificación.
  • Recuperación automática: En ciertos dispositivos, Servicios de Google Play puede detectar automáticamente el SMS de verificación entrante y realizar la verificación sin que el usuario intervenga. Es posible que esta opción no esté disponible con algunos proveedores.
En ambos casos, el número de teléfono del usuario se verificó correctamente, por lo que se puede usar el objeto PhoneAuthCredential que se pasó a la devolución de llamada para que el usuario acceda.

onVerificationFailed(FirebaseException)

Este método se llama como respuesta a una solicitud de verificación no válida, como una solicitud que especifica un número de teléfono o un código de verificación no válido.

onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken)

Opcional. Este método se llama luego de enviar por SMS el código de verificación al número de teléfono proporcionado.

Cuando se llama este método, la mayoría de las apps muestran una IU que le pide al usuario escribir el código de verificación que recibió por SMS. La verificación se podría estar realizando en segundo plano al mismo tiempo. Luego de que el usuario escriba el código de verificación, podrás usarlo junto con el ID de verificación que se pasó al método para crear un objeto PhoneAuthCredential, que puedes usar para que el usuario acceda. Sin embargo, es posible que algunas apps esperen hasta que se llame a onCodeAutoRetrievalTimeOut para mostrar la IU del código de verificación (no se recomienda).

onCodeAutoRetrievalTimeOut(String verificationId)

Opcional. Este método se llama después de que pasa el tiempo de espera especificado en verifyPhoneNumber sin que se active onVerificationCompleted antes. En los dispositivos que no tienen tarjeta SIM, este método se llama de inmediato, debido a que no se puede realizar una recuperación automática de SMS.

Algunas apps bloquean los datos de entrada del usuario hasta que termine el tiempo de espera del período de verificación automática y solo en ese momento muestran una IU que le pide al usuario escribir el código de verificación que recibió por SMS (no se recomienda).

Crea un objeto PhoneAuthCredential

Después de que el usuario ingrese el código de verificación que Firebase le envió a su teléfono, crea un objeto PhoneAuthCredential con el código y el ID de verificación que se pasaron a la devolución de llamada onCodeSent u onCodeAutoRetrievalTimeOut Nota: Cuando se llama a onVerificationCompleted, recibes un objeto PhoneAuthCredential directamente, por lo que puedes omitir este paso.

Para crear el objeto PhoneAuthCredential, llama a PhoneAuthProvider.getCredential:

Java
Android

PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);

Kotlin
Android

val credential = PhoneAuthProvider.getCredential(verificationId!!, code)

Acceso del usuario

Después de que recibas el objeto PhoneAuthCredential, ya sea en la devolución de llamada onVerificationCompleted o mediante una llamada a PhoneAuthProvider.getCredential, completa el flujo de acceso mediante el paso del objeto PhoneAuthCredential a FirebaseAuth.signInWithCredential:

Java
Android

private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {
    mAuth.signInWithCredential(credential)
            .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        // Sign in success, update UI with the signed-in user's information
                        Log.d(TAG, "signInWithCredential:success");

                        FirebaseUser user = task.getResult().getUser();
                        // ...
                    } else {
                        // Sign in failed, display a message and update the UI
                        Log.w(TAG, "signInWithCredential:failure", task.getException());
                        if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {
                            // The verification code entered was invalid
                        }
                    }
                }
            });
}

Kotlin
Android

private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
    auth.signInWithCredential(credential)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCredential:success")

                    val user = task.result?.user
                    // ...
                } else {
                    // Sign in failed, display a message and update the UI
                    Log.w(TAG, "signInWithCredential:failure", task.exception)
                    if (task.exception is FirebaseAuthInvalidCredentialsException) {
                        // The verification code entered was invalid
                    }
                }
            }
}

Prueba con números de teléfono incluidos en la lista blanca

Puedes incluir números de teléfono para desarrollo en la lista blanca a través de Firebase console. Una lista blanca de números de teléfono ofrece los siguientes beneficios:

  • Prueba la autenticación del número de teléfono sin consumir tu cuota de uso.
  • Prueba la autenticación del número de teléfono sin enviar un mensaje SMS real.
  • Ejecuta pruebas consecutivas con el mismo número de teléfono sin regulación. Esto minimiza el riesgo de rechazo durante el proceso de revisión de la tienda de aplicaciones si el revisor utiliza el mismo número de teléfono para las pruebas.
  • Realiza pruebas con facilidad en entornos de desarrollo sin ningún esfuerzo adicional, por ejemplo, obtén la capacidad de desarrollar en un simulador de iOS o un emulador de Android sin los Servicios de Google Play.
  • Escribe pruebas de integración sin ser bloqueado por los controles de seguridad que normalmente se aplican a los números de teléfono reales en un entorno de producción.

Para incluir números de teléfono en la lista blanca, es necesario cumplir estos requisitos:

  1. Asegúrate de usar números ficticios que aún no existan. Firebase Authentication no permite incluir en la lista blanca números de teléfono existentes, que tengan usuarios reales. Una opción es usar números con el prefijo 555 como números de teléfono de prueba de EE.UU., por ejemplo: +1 650-555-3434.
  2. Los números de teléfono deben tener el formato adecuado de longitud y otras restricciones. Estos números pasarán por la misma validación que el número de teléfono de un usuario real.
  3. Puedes agregar hasta 10 números de teléfono.
  4. Usa códigos o números de teléfono de prueba que sean difíciles de adivinar y cámbialos con frecuencia.

Incluye números de teléfono y códigos de verificación en la lista blanca

  1. En Firebase console, abre la sección Authentication.
  2. En la pestaña Método de acceso, habilita el proveedor de telefonía, si todavía no lo has hecho.
  3. Abre el menú de acordeón Números de teléfono para la prueba.
  4. Proporciona el número de teléfono que deseas probar, por ejemplo: +1 650-555-3434.
  5. Proporciona el código de verificación de 6 dígitos para ese número específico, por ejemplo: 654321.
  6. Agrega el número. Si es necesario, puedes desplazarte sobre la fila correspondiente y hacer clic en el ícono de papelera para borrar el número de teléfono y su código.

Pruebas manuales

En tu aplicación, puedes comenzar a usar directamente un número de teléfono incluido en la lista blanca. Esto te permite realizar pruebas manuales durante las etapas de desarrollo sin que te encuentres con problemas de cuota o regulación. También puedes realizar pruebas directamente desde un simulador de iOS o un emulador de Android sin tener los Servicios de Google Play instalados.

Cuando se proporciona el número de teléfono incluido en la lista blanca y se envía el código de verificación, no se envía ningún SMS real. En lugar de eso, es necesario proporcionar el código de verificación previamente configurado para completar el acceso.

Cuando se completa el acceso, se crea un usuario de Firebase con ese número de teléfono. El usuario tiene el mismo comportamiento y las mismas propiedades que el usuario de un número de teléfono real, y puede acceder de la misma manera a Realtime Database, Cloud Firestore y otros servicios. El token de ID emitido durante este proceso tiene la misma firma que el usuario de un número de teléfono real.

Otra opción es configurar una función de prueba mediante reclamaciones personalizadas en estos usuarios para diferenciarlos como usuarios falsos si se desea restringir más el acceso.

Pruebas de integración

Además de las pruebas manuales, Firebase Authentication proporciona las API con las que es posible escribir pruebas de integración para la autenticación del teléfono. Para inhabilitar la verificación de app, estas API inhabilitan el requisito reCAPTCHA en las notificaciones push silenciosas y web en iOS. Esto permite que se realicen las pruebas de automatización en estos flujos y facilita su implementación. Además, las API proporcionan la capacidad de probar flujos de verificación instantánea en Android.

En Android, puedes usar los números de teléfono incluidos en la lista blanca con facilidad, sin ninguna llamada a la API adicional. Una llamada a verifyPhoneNumber con un número incluido en la lista blanca activa la devolución de llamada onCodeSent, en la que es necesario proporcionar el código de verificación correspondiente. Esto permite realizar pruebas en emuladores de Android.

Java
Android

String phoneNum = "+16505554567";
String testVerificationCode = "123456";

// Whenever verification is triggered with the whitelisted number,
// provided it is not set for auto-retrieval, onCodeSent will be triggered.
PhoneAuthProvider.getInstance().verifyPhoneNumber(
        phoneNum, 30L /*timeout*/, TimeUnit.SECONDS,
        this, new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

            @Override
            public void onCodeSent(String verificationId,
                                   PhoneAuthProvider.ForceResendingToken forceResendingToken) {
                // Save the verification id somewhere
                // ...

                // The corresponding whitelisted code above should be used to complete sign-in.
                MainActivity.this.enableUserManuallyInputCode();
            }

            @Override
            public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) {
                // Sign in with the credential
                // ...
            }

            @Override
            public void onVerificationFailed(FirebaseException e) {
                 // ...
            }

        });

Kotlin
Android

val phoneNum = "+16505554567"
val testVerificationCode = "123456"

// Whenever verification is triggered with the whitelisted number,
// provided it is not set for auto-retrieval, onCodeSent will be triggered.
PhoneAuthProvider.getInstance().verifyPhoneNumber(
        phoneNum, 30L /*timeout*/, TimeUnit.SECONDS,
        this, object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

    override fun onCodeSent(
        verificationId: String?,
        forceResendingToken: PhoneAuthProvider.ForceResendingToken?
    ) {
        // Save the verification id somewhere
        // ...

        // The corresponding whitelisted code above should be used to complete sign-in.
        this@MainActivity.enableUserManuallyInputCode()
    }

    override fun onVerificationCompleted(phoneAuthCredential: PhoneAuthCredential) {
        // Sign in with the credential
        // ...
    }

    override fun onVerificationFailed(e: FirebaseException) {
        // ...
    }
})

Además, puedes probar los flujos de recuperación automática en Android. Para ello, configura el número incluido en la lista blanca y el código de verificación correspondiente para recuperación automática mediante una llamada a setAutoRetrievedSmsCodeForPhoneNumber.

Una llamada a verifyPhoneNumber activa onVerificationCompleted con PhoneAuthCredential de forma directa. Esto funciona solo con números de teléfono incluidos en una lista blanca.

Asegúrate de que esto esté inhabilitado y que ningún número de teléfono incluido en la lista blanca esté codificado en tu app cuando la publiques en Google Play Store.

Java
Android

// The test phone number and code should be whitelisted in the console.
String phoneNumber = "+16505554567";
String smsCode = "123456";

FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
FirebaseAuthSettings firebaseAuthSettings = firebaseAuth.getFirebaseAuthSettings();

// Configure faking the auto-retrieval with the whitelisted numbers.
firebaseAuthSettings.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode);

PhoneAuthProvider phoneAuthProvider = PhoneAuthProvider.getInstance();
phoneAuthProvider.verifyPhoneNumber(
        phoneNumber,
        60L,
        TimeUnit.SECONDS,
        this, /* activity */
        new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            @Override
            public void onVerificationCompleted(PhoneAuthCredential credential) {
                // Instant verification is applied and a credential is directly returned.
                // ...
            }

            // ...
        });

Kotlin
Android

// The test phone number and code should be whitelisted in the console.
val phoneNumber = "+16505554567"
val smsCode = "123456"

val firebaseAuth = FirebaseAuth.getInstance()
val firebaseAuthSettings = firebaseAuth.firebaseAuthSettings

// Configure faking the auto-retrieval with the whitelisted numbers.
firebaseAuthSettings.setAutoRetrievedSmsCodeForPhoneNumber(phoneNumber, smsCode)

val phoneAuthProvider = PhoneAuthProvider.getInstance()
phoneAuthProvider.verifyPhoneNumber(
        phoneNumber,
        60L,
        TimeUnit.SECONDS,
        this, /* activity */
        object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            override fun onVerificationCompleted(credential: PhoneAuthCredential) {
                // Instant verification is applied and a credential is directly returned.
                // ...
            }

            // ...
        })

Pasos siguientes

Cuando un usuario accede por primera vez, se crea una cuenta de usuario nueva y se la vincula con las credenciales (el nombre de usuario y la contraseña, el número de teléfono o la información del proveedor de autenticación) que el usuario usó para acceder. Esta cuenta se almacena como parte de tu proyecto de Firebase y se puede usar para identificar a un usuario en todas las apps del proyecto, sin importar cómo acceda.

  • En las apps, puedes obtener la información básica del perfil del usuario a partir del objeto FirebaseUser. Consulta Administra usuarios.

  • En las reglas de seguridad de Firebase Realtime Database y Cloud Storage, puedes obtener el ID único del usuario que accedió a partir de la variable auth y usarlo para controlar a qué datos podrá acceder.

Si quieres permitir que los usuarios accedan a la app con varios proveedores de autenticación, vincula las credenciales de proveedores de autenticación a una cuenta de usuario existente.

Para cerrar la sesión de un usuario, llama a signOut de la siguiente manera:

Java
Android

FirebaseAuth.getInstance().signOut();

Kotlin
Android

FirebaseAuth.getInstance().signOut()