Autenticar usando Apple en Android

Puede permitir que sus usuarios se autentiquen con Firebase usando su ID de Apple mediante el SDK de Firebase para llevar a cabo el flujo de inicio de sesión de OAuth 2.0 de un extremo a otro.

Antes de que empieces

Para iniciar sesión como usuario con Apple, primero configure Iniciar sesión con Apple en el sitio para desarrolladores de Apple y luego habilite Apple como proveedor de inicio de sesión para su proyecto de Firebase.

Únase al programa de desarrolladores de Apple

Iniciar sesión con Apple solo lo pueden configurar los miembros del Programa de desarrolladores de Apple .

Configurar Iniciar sesión con Apple

En el sitio para desarrolladores de Apple , haga lo siguiente:

  1. Asocie su sitio web con su aplicación como se describe en la primera sección de Configurar el inicio de sesión con Apple para la web . Cuando se le solicite, registre la siguiente URL como URL de retorno:

    https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler

    Puede obtener el ID de su proyecto de Firebase en la página de configuración de la consola de Firebase .

    Cuando haya terminado, tome nota de su nuevo ID de servicio, que necesitará en la siguiente sección.

  2. Cree un inicio de sesión con la clave privada de Apple . Necesitará su nueva clave privada y su ID de clave en la siguiente sección.
  3. Si utiliza cualquiera de las funciones de Firebase Authentication que envían correos electrónicos a los usuarios, incluido el inicio de sesión mediante enlace de correo electrónico, la verificación de la dirección de correo electrónico, la revocación de cambio de cuenta y otras, configure el servicio de retransmisión de correo electrónico privado de Apple y regístrese noreply@ YOUR_FIREBASE_PROJECT_ID .firebaseapp.com (o su dominio de plantilla de correo electrónico personalizado) para que Apple pueda transmitir los correos electrónicos enviados mediante Firebase Authentication a direcciones de correo electrónico anónimas de Apple.

Habilite Apple como proveedor de inicio de sesión

  1. Agrega Firebase a tu proyecto de Android . Asegúrese de registrar la firma SHA-1 de su aplicación cuando la configure en Firebase console.
  2. En Firebase console , abre la sección Auth . En la pestaña Método de inicio de sesión , habilite el proveedor de Apple . Especifique el ID de servicio que creó en la sección anterior. Además, en la sección de configuración del flujo de código OAuth , especifique su ID de equipo Apple y la clave privada y el ID de clave que creó en la sección anterior.

Cumplir con los requisitos de datos anonimizados de Apple

Iniciar sesión con Apple ofrece a los usuarios la opción de anonimizar sus datos, incluida su dirección de correo electrónico, al iniciar sesión. Los usuarios que eligen esta opción tienen direcciones de correo electrónico con el dominio privaterelay.appleid.com . Cuando utiliza Iniciar sesión con Apple en su aplicación, debe cumplir con las políticas o términos de desarrollador aplicables de Apple con respecto a estos ID de Apple anónimos.

Esto incluye obtener el consentimiento del usuario requerido antes de asociar cualquier información personal de identificación directa con una ID de Apple anónima. Cuando se utiliza la autenticación de Firebase, esto puede incluir las siguientes acciones:

  • Vincula una dirección de correo electrónico a una ID de Apple anónima o viceversa.
  • Vincular un número de teléfono a una ID de Apple anónima o viceversa
  • Vincula una credencial social no anónima (Facebook, Google, etc.) a una ID de Apple anónima o viceversa.

La lista de arriba no es exhaustiva. Consulte el Acuerdo de licencia del programa para desarrolladores de Apple en la sección Membresía de su cuenta de desarrollador para asegurarse de que su aplicación cumpla con los requisitos de Apple.

Maneja el flujo de inicio de sesión con el SDK de Firebase

En Android, la forma más sencilla de autenticar a sus usuarios con Firebase utilizando sus cuentas de Apple es manejar todo el flujo de inicio de sesión con el SDK de Firebase para Android.

Para manejar el flujo de inicio de sesión con el SDK de Firebase para Android, siga estos pasos:

  1. Construya una instancia de OAuthProvider usando su Builder con el ID de proveedor apple.com :

    Kotlin+KTX

    val provider = OAuthProvider.newBuilder("apple.com")
    

    Java

    OAuthProvider.Builder provider = OAuthProvider.newBuilder("apple.com");
    
  2. Opcional: Especifique ámbitos de OAuth 2.0 adicionales además del valor predeterminado que desea solicitar al proveedor de autenticación.

    Kotlin+KTX

    provider.setScopes(arrayOf("email", "name"))
    

    Java

    List<String> scopes =
        new ArrayList<String>() {
          {
            add("email");
            add("name");
          }
        };
    provider.setScopes(scopes);
    

    De forma predeterminada, cuando se habilita Una cuenta por dirección de correo electrónico , Firebase solicita ámbitos de nombre y correo electrónico. Si cambia esta configuración a Varias cuentas por dirección de correo electrónico , Firebase no solicita ningún ámbito a Apple a menos que los especifique.

  3. Opcional: si desea mostrar la pantalla de inicio de sesión de Apple en un idioma que no sea inglés, configure el parámetro locale . Consulte los documentos Iniciar sesión con Apple para conocer las configuraciones regionales admitidas.

    Kotlin+KTX

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr")
    

    Java

    // Localize the Apple authentication screen in French.
    provider.addCustomParameter("locale", "fr");
    
  4. Autentíquese con Firebase utilizando el objeto proveedor de OAuth. Tenga en cuenta que, a diferencia de otras operaciones FirebaseAuth , esto tomará el control de su interfaz de usuario al abrir una pestaña personalizada de Chrome. En consecuencia, no haga referencia a su actividad en OnSuccessListener y OnFailureListener que adjunte, ya que se desconectarán inmediatamente cuando la operación inicie la interfaz de usuario.

    Primero debes verificar si ya has recibido una respuesta. Iniciar sesión con este método coloca su actividad en segundo plano, lo que significa que el sistema puede reclamarla durante el flujo de inicio de sesión. Para asegurarse de que no haga que el usuario vuelva a intentarlo si esto sucede, debe verificar si ya hay un resultado presente.

    Para comprobar si hay un resultado pendiente, llame getPendingAuthResult() :

    Kotlin+KTX

    val pending = auth.pendingAuthResult
    if (pending != null) {
        pending.addOnSuccessListener { authResult ->
            Log.d(TAG, "checkPending:onSuccess:$authResult")
            // Get the user profile with authResult.getUser() and
            // authResult.getAdditionalUserInfo(), and the ID
            // token from Apple with authResult.getCredential().
        }.addOnFailureListener { e ->
            Log.w(TAG, "checkPending:onFailure", e)
        }
    } else {
        Log.d(TAG, "pending: null")
    }
    

    Java

    mAuth = FirebaseAuth.getInstance();
    Task<AuthResult> pending = mAuth.getPendingAuthResult();
    if (pending != null) {
        pending.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
            @Override
            public void onSuccess(AuthResult authResult) {
                Log.d(TAG, "checkPending:onSuccess:" + authResult);
                // Get the user profile with authResult.getUser() and
                // authResult.getAdditionalUserInfo(), and the ID
                // token from Apple with authResult.getCredential().
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.w(TAG, "checkPending:onFailure", e);
            }
        });
    } else {
        Log.d(TAG, "pending: null");
    }
    

    Si no hay ningún resultado pendiente, inicie el flujo de inicio de sesión llamando a startActivityForSignInWithProvider() :

    Kotlin+KTX

    auth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener { authResult ->
                // Sign-in successful!
                Log.d(TAG, "activitySignIn:onSuccess:${authResult.user}")
                val user = authResult.user
                // ...
            }
            .addOnFailureListener { e ->
                Log.w(TAG, "activitySignIn:onFailure", e)
            }
    

    Java

    mAuth.startActivityForSignInWithProvider(this, provider.build())
            .addOnSuccessListener(
                    new OnSuccessListener<AuthResult>() {
                        @Override
                        public void onSuccess(AuthResult authResult) {
                            // Sign-in successful!
                            Log.d(TAG, "activitySignIn:onSuccess:" + authResult.getUser());
                            FirebaseUser user = authResult.getUser();
                            // ...
                        }
                    })
            .addOnFailureListener(
                    new OnFailureListener() {
                        @Override
                        public void onFailure(@NonNull Exception e) {
                            Log.w(TAG, "activitySignIn:onFailure", e);
                        }
                    });
    

    A diferencia de otros proveedores compatibles con Firebase Auth, Apple no proporciona una URL de foto.

    Además, cuando el usuario elige no compartir su correo electrónico con la aplicación, Apple proporciona una dirección de correo electrónico única para ese usuario (del formato xyz@privaterelay.appleid.com ), que comparte con su aplicación. Si configuró el servicio de retransmisión de correo electrónico privado, Apple reenvía los correos electrónicos enviados a la dirección anónima a la dirección de correo electrónico real del usuario.

    Apple solo comparte información del usuario, como el nombre para mostrar, con las aplicaciones la primera vez que un usuario inicia sesión. Por lo general, Firebase almacena el nombre para mostrar la primera vez que un usuario inicia sesión en Apple, que puede obtener con getCurrentUser().getDisplayName() . Sin embargo, si anteriormente usaste Apple para iniciar sesión como usuario en la aplicación sin usar Firebase, Apple no proporcionará a Firebase el nombre para mostrar del usuario.

Reautenticación y vinculación de cuentas

Se puede usar el mismo patrón con startActivityForReauthenticateWithProvider() , que puede usar para recuperar una credencial nueva para operaciones confidenciales que requieren un inicio de sesión reciente:

Kotlin+KTX

// The user is already signed-in.
val firebaseUser = auth.getCurrentUser()

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener( authResult -> {
        // User is re-authenticated with fresh tokens and
        // should be able to perform sensitive operations
        // like account deletion and email or password
        // update.
    })
    .addOnFailureListener( e -> {
        // Handle failure.
    })

Java

// The user is already signed-in.
FirebaseUser firebaseUser = mAuth.getCurrentUser();

firebaseUser
    .startActivityForReauthenticateWithProvider(/* activity= */ this, provider.build())
    .addOnSuccessListener(
        new OnSuccessListener<AuthResult>() {
          @Override
          public void onSuccess(AuthResult authResult) {
            // User is re-authenticated with fresh tokens and
            // should be able to perform sensitive operations
            // like account deletion and email or password
            // update.
          }
        })
    .addOnFailureListener(
        new OnFailureListener() {
          @Override
          public void onFailure(@NonNull Exception e) {
            // Handle failure.
          }
        });

Y puede utilizar linkWithCredential() para vincular diferentes proveedores de identidad a cuentas existentes.

Tenga en cuenta que Apple requiere que obtenga el consentimiento explícito de los usuarios antes de vincular sus cuentas de Apple a otros datos.

Por ejemplo, para vincular una cuenta de Facebook a la cuenta actual de Firebase, use el token de acceso que obtuvo al iniciar sesión como usuario en Facebook:

Kotlin+KTX

// Initialize a Facebook credential with a Facebook access token.
val credential = FacebookAuthProvider.getCredential(token.getToken())

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, task -> {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      });

Java

// Initialize a Facebook credential with a Facebook access token.
AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken());

// Assuming the current user is an Apple user linking a Facebook provider.
mAuth.getCurrentUser().linkWithCredential(credential)
    .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
      @Override
      public void onComplete(@NonNull Task<AuthResult> task) {
        if (task.isSuccessful()) {
          // Facebook credential is linked to the current Apple user.
          // The user can now sign in to the same account
          // with either Apple or Facebook.
        }
      }
    });

Avanzado: Manejar el flujo de inicio de sesión manualmente

También puede autenticarse con Firebase usando una cuenta de Apple manejando el flujo de inicio de sesión mediante el SDK JS de inicio de sesión de Apple, creando manualmente el flujo de OAuth o usando una biblioteca de OAuth como AppAuth .

  1. Para cada solicitud de inicio de sesión, genere una cadena aleatoria (un "nonce") que usará para asegurarse de que el token de identificación que obtenga se haya otorgado específicamente en respuesta a la solicitud de autenticación de su aplicación. Este paso es importante para evitar ataques de repetición.

    Puedes generar un nonce criptográficamente seguro en Android con SecureRandom , como en el siguiente ejemplo:

    Kotlin+KTX

    private fun generateNonce(length: Int): String {
        val generator = SecureRandom()
    
        val charsetDecoder = StandardCharsets.US_ASCII.newDecoder()
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE)
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE)
    
        val bytes = ByteArray(length)
        val inBuffer = ByteBuffer.wrap(bytes)
        val outBuffer = CharBuffer.allocate(length)
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes)
            inBuffer.rewind()
            charsetDecoder.reset()
            charsetDecoder.decode(inBuffer, outBuffer, false)
        }
        outBuffer.flip()
        return outBuffer.toString()
    }
    

    Java

    private String generateNonce(int length) {
        SecureRandom generator = new SecureRandom();
    
        CharsetDecoder charsetDecoder = StandardCharsets.US_ASCII.newDecoder();
        charsetDecoder.onUnmappableCharacter(CodingErrorAction.IGNORE);
        charsetDecoder.onMalformedInput(CodingErrorAction.IGNORE);
    
        byte[] bytes = new byte[length];
        ByteBuffer inBuffer = ByteBuffer.wrap(bytes);
        CharBuffer outBuffer = CharBuffer.allocate(length);
        while (outBuffer.hasRemaining()) {
            generator.nextBytes(bytes);
            inBuffer.rewind();
            charsetDecoder.reset();
            charsetDecoder.decode(inBuffer, outBuffer, false);
        }
        outBuffer.flip();
        return outBuffer.toString();
    }
    

    Luego, obtenga el hash SHA246 del nonce como una cadena hexadecimal:

    Kotlin+KTX

    private fun sha256(s: String): String {
        val md = MessageDigest.getInstance("SHA-256")
        val digest = md.digest(s.toByteArray())
        val hash = StringBuilder()
        for (c in digest) {
            hash.append(String.format("%02x", c))
        }
        return hash.toString()
    }
    

    Java

    private String sha256(String s) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] digest = md.digest(s.getBytes());
        StringBuilder hash = new StringBuilder();
        for (byte c: digest) {
            hash.append(String.format("%02x", c));
        }
        return hash.toString();
    }
    

    Enviará el hash SHA256 del nonce con su solicitud de inicio de sesión, que Apple pasará sin cambios en la respuesta. Firebase valida la respuesta aplicando hash al nonce original y comparándolo con el valor pasado por Apple.

  2. Inicie el flujo de inicio de sesión de Apple utilizando su biblioteca OAuth u otro método. Asegúrese de incluir el nonce hash como parámetro en su solicitud.

  3. Después de recibir la respuesta de Apple, obtenga el token de identificación de la respuesta y utilícelo junto con el nonce sin hash para crear una AuthCredential :

    Kotlin+KTX

    val credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build()
    

    Java

    AuthCredential credential =  OAuthProvider.newCredentialBuilder("apple.com")
        .setIdTokenWithRawNonce(appleIdToken, rawUnhashedNonce)
        .build();
    
  4. Autenticarse con Firebase usando la credencial de Firebase:

    Kotlin+KTX

    auth.signInWithCredential(credential)
          .addOnCompleteListener(this) { task ->
              if (task.isSuccessful) {
                // User successfully signed in with Apple ID token.
                // ...
              }
          }
    

    Java

    mAuth.signInWithCredential(credential)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
          @Override
          public void onComplete(@NonNull Task<AuthResult> task) {
            if (task.isSuccessful()) {
              // User successfully signed in with Apple ID token.
              // ...
            }
          }
        });
    

Si la llamada a signInWithCredential tiene éxito, puede utilizar el método getCurrentUser para obtener los datos de la cuenta del usuario.

Revocación de token

Apple exige que las aplicaciones que admiten la creación de cuentas permitan a los usuarios iniciar la eliminación de su cuenta dentro de la aplicación, como se describe en las Pautas de revisión de la App Store.

Además, las aplicaciones que admiten Iniciar sesión con Apple deben utilizar la API REST Iniciar sesión con Apple para revocar tokens de usuario.

Para cumplir con este requisito, implemente los siguientes pasos:

  1. Utilice el método startActivityForSignInWithProvider() para iniciar sesión con Apple y obtener AuthResult .

  2. Obtenga el token de acceso para el proveedor de Apple.

    Kotlin+KTX

    val oauthCredential: OAuthCredential =  authResult.credential
    val accessToken = oauthCredential.accessToken
    

    Java

    OAuthCredential oauthCredential = (OAuthCredential) authResult.getCredential();
    String accessToken = oauthCredential.getAccessToken();
    
  3. Revocar el token mediante la API revokeAccessToken .

    Kotlin+KTX

    mAuth.revokeAccessToken(accessToken)
      .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
          // Access token successfully revoked
          // for the user ...
        }
    }
    

    Java

    mAuth.revokeAccessToken(accessToken)
        .addOnCompleteListener(this, new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
              if (task.isSuccessful()) {
                // Access token successfully revoked
                // for the user ...
              }
            }
      });
    
  1. Finalmente, elimine la cuenta de usuario (y todos los datos asociados)

    Próximos pasos

    Después de que un usuario inicia sesión por primera vez, se crea una nueva cuenta de usuario y se vincula a las credenciales (es decir, el nombre de usuario y la contraseña, el número de teléfono o la información del proveedor de autenticación) con las que el usuario inició sesión. Esta nueva cuenta se almacena como parte de su proyecto de Firebase y se puede usar para identificar a un usuario en cada aplicación de su proyecto, independientemente de cómo inicie sesión el usuario.

    • En tus aplicaciones, puedes obtener la información básica del perfil del usuario desde el objeto FirebaseUser . Consulte Administrar usuarios .

    • En las reglas de seguridad de Firebase Realtime Database y Cloud Storage, puede obtener el ID de usuario único del usuario que inició sesión a partir de la variable auth y usarlo para controlar a qué datos puede acceder un usuario.

    Puede permitir que los usuarios inicien sesión en su aplicación utilizando múltiples proveedores de autenticación vinculando las credenciales del proveedor de autenticación a una cuenta de usuario existente.

    Para cerrar la sesión de un usuario, llame signOut :

    Kotlin+KTX

    Firebase.auth.signOut()

    Java

    FirebaseAuth.getInstance().signOut();