Ir para o console

Autenticar com o Firebase usando link por e-mail no Android

Use o Firebase Authentication para fazer o login de um usuário por meio de um link enviado a ele por e-mail. Nesse processo, o endereço de e-mail do usuário também é verificado.

O login por e-mail tem inúmeras vantagens:

  • Inscrição e login menos complicados.
  • Menos chances de reutilizar senhas entre os aplicativos, o que poderia diminuir a segurança até mesmo das senhas mais fortes.
  • Capacidade de autenticar o usuário e verificar se ele é o legítimo proprietário do endereço de e-mail.
  • O usuário só precisa de uma conta de e-mail acessível para fazer login. Não são necessários número de telefone ou conta em redes sociais.
  • O usuário faz login com segurança sem precisar fornecer ou lembrar uma senha, ações que podem ser incômodas em dispositivos móveis.
  • O usuário que já tiver feito login com um identificador de e-mail (senha ou federado) poderá se conectar posteriormente apenas com o e-mail. Por exemplo, se ele se esquecer da senha, ainda será possível fazer login sem precisar redefini-la.

Antes de começar

Configurar seu projeto do Android Studio

  1. Adicione o Firebase ao projeto do Android.
  2. Adicione as dependências do Firebase Authentication e do Google Play Services ao arquivo build.gradle no nível do app:
    implementation 'com.google.firebase:firebase-auth:16.1.0'
    implementation 'com.google.android.gms:play-services-auth:16.0.1'
    

Para que os usuários façam login usando um link enviado por e-mail, primeiro ative o provedor de e-mail e o método de login por link no projeto do Firebase:

  1. No Console do Firebase, abra a seção Auth.
  2. Na guia Método de login, ative o provedor de E-mail/senha. Lembre-se de que você precisa ativar esse método para poder usar o login por link.
  3. Na mesma seção, ative o método Link do e-mail (login sem senha).
  4. Clique em Salvar.

Para iniciar o fluxo de autenticação, forneça ao usuário uma interface que solicite o endereço de e-mail dele. Depois, chame sendSignInLinkToEmail para solicitar que o Firebase envie o link de autenticação a esse e-mail.

  1. Crie o objeto ActionCodeSettings, que fornece instruções ao Firebase para gerar o link do e-mail. Defina os seguintes campos:

    • url: o link direto a ser incorporado e qualquer estado adicional a ser transmitido junto. É preciso que o domínio do link esteja na lista de permissões de domínios autorizados do Console do Firebase, encontrada na guia "Método de login" (Autenticação -> Método de login). O link redirecionará o usuário para esse URL se o aplicativo não estiver e não puder ser instalado no dispositivo.
    • androidPackageName e IOSBundleId: os apps a serem usados quando o usuário abrir o link para login em um dispositivo Android ou iOS. Saiba mais sobre como configurar o Firebase Dynamic Links para abrir links de ação por e-mail via aplicativos para dispositivos móveis.
    • handleCodeInApp: definido como true. É necessário sempre concluir o processo de login no app, ao contrário de outras ações fora de banda, como redefinição de senha e verificação de e-mail. Isso acontece porque o usuário precisa estar conectado e com o estado Auth mantido no app ao final do fluxo.
    • dynamicLinkDomain: quando vários domínios de link dinâmico customizados são definidos em um projeto, especifique qual deles usar se o link precisar ser aberto em um determinado app para dispositivos móveis (por exemplo, example.page.link). Caso contrário, o primeiro domínio será selecionado automaticamente.

    Java
    Android

    ActionCodeSettings actionCodeSettings =
            ActionCodeSettings.newBuilder()
                    // URL you want to redirect back to. The domain (www.example.com) for this
                    // URL must be whitelisted in the Firebase Console.
                    .setUrl("https://www.example.com/finishSignUp?cartId=1234")
                    // This must be true
                    .setHandleCodeInApp(true)
                    .setIOSBundleId("com.example.ios")
                    .setAndroidPackageName(
                            "com.example.android",
                            true, /* installIfNotAvailable */
                            "12"    /* minimumVersion */)
                    .build();

    Kotlin
    Android

    val actionCodeSettings = ActionCodeSettings.newBuilder()
            // URL you want to redirect back to. The domain (www.example.com) for this
            // URL must be whitelisted in the Firebase Console.
            .setUrl("https://www.example.com/finishSignUp?cartId=1234")
            // This must be true
            .setHandleCodeInApp(true)
            .setIOSBundleId("com.example.ios")
            .setAndroidPackageName(
                    "com.example.android",
                    true, /* installIfNotAvailable */
                    "12" /* minimumVersion */)
            .build()

    Para saber mais sobre ActionCodeSettings, consulte a seção Como transmitir o estado nas ações de e-mail.

  2. Solicite o e-mail ao usuário.

  3. Envie o link de autenticação a esse endereço e salve o e-mail caso o usuário conclua o login no mesmo dispositivo.

    Java
    Android

    FirebaseAuth auth = FirebaseAuth.getInstance();
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Email sent.");
                    }
                }
            });

    Kotlin
    Android

    val auth = FirebaseAuth.getInstance()
    auth.sendSignInLinkToEmail(email, actionCodeSettings)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "Email sent.")
                }
            }

Preocupações com segurança

No Firebase Auth, o usuário precisa fornecer o endereço de e-mail ao concluir o fluxo de login. Isso evita que o link seja usado para fazer o login de um usuário indesejado ou em um dispositivo não intencional. Para realizar o login, esse endereço precisa ser igual ao e-mail que recebeu o link.

É possível simplificar o fluxo dos usuários que abrem o link no mesmo dispositivo usado para solicitá-lo. Basta armazenar o endereço deles localmente quando enviar o e-mail de login. Por exemplo, você pode usar o SharedPreferences. Depois, utilize o endereço para concluir o fluxo. Não transmita o e-mail do usuário nos parâmetros de URL de redirecionamento e o reutilize, já que isso pode ativar injeções de sessão.

Após a conclusão do login, qualquer mecanismo anterior de login não verificado será removido do usuário, e todas as sessões existentes serão invalidadas. Por exemplo, se alguém tiver criado uma conta não verificada com a mesma senha e e-mail, a senha do usuário será removida. Isso impede que a pessoa que reivindicou a propriedade e criou essa conta faça login novamente com o e-mail e senha não confirmados.

Além disso, não deixe de usar um URL HTTPS na produção para impedir que o link possa ser interceptado por servidores intermediários.

Como concluir o login em um app para Android

O Firebase Authentication usa o Firebase Dynamic Links para enviar o link por e-mail a um dispositivo móvel. No aplicativo para dispositivos móveis, ele precisa estar configurado para detectar o link de entrada, analisar o link direto subjacente e então concluir o login.

O Firebase Auth usa o Firebase Dynamic Links ao enviar um link que deve ser aberto em um aplicativo para dispositivos móveis. Para usar esse recurso, os links dinâmicos precisam estar configurados no Console do Firebase.

  1. Ative o Firebase Dynamic Links:

    1. No Console do Firebase, abra a seção Dynamic Links.
    2. Caso ainda não tenha aceitado os termos do Dynamic Links e criado um domínio do Dynamic Links, faça isso agora.

      Se você já tiver criado um domínio do Dynamic Links, anote-o. Um domínio do Dynamic Links costuma se parecer com este exemplo:

      example.page.link

      Você precisará desse valor ao configurar o app para Android ou iOS para interceptar o link recebido.

  2. Configurar aplicativos Android:

    1. Para lidar com esses links a partir do aplicativo para Android, o nome do pacote para Android precisa ser especificado nas configurações do projeto do Console do Firebase. Além disso, o SHA-1 e o SHA-256 do certificado do aplicativo precisam ser fornecidos.
    2. Agora que você adicionou um domínio de link dinâmico e garantiu que seu aplicativo para Android esteja configurado corretamente, o link dinâmico será redirecionado para seu aplicativo a partir da atividade do iniciador.
    3. Se você quiser que o link dinâmico redirecione para uma atividade específica, será necessário configurar um filtro de intent no seu arquivo AndroidManifest.xml. Para isso, basta especificar seu domínio de link dinâmico ou o gerenciador de ações de e-mail no filtro de intent. Por padrão, o gerenciador de ações de e-mail é hospedado em um domínio como o exemplo a seguir:
      PROJECT_ID.firebaseapp.com/
    4. Advertências:
      1. Não especifique o URL que você definiu no actionCodeSettings no seu filtro de intent.
      2. Ao criar seu domínio de link dinâmico, você também pode ter criado um link de URL curto. Esse URL curto não será transmitido. Não configure seu filtro de intent para capturá-lo com um atributo android:pathPrefix. Isso significa que você não poderá capturar links dinâmicos diferentes em diferentes partes do seu aplicativo. No entanto, você pode verificar o parâmetro de consulta do mode no link para ver qual operação está tentando ser executada ou usar métodos do SDK, como isSignInWithEmailLink para ver se um link recebido pelo seu app faz o que você quer.
    5. Para mais informações sobre como receber links dinâmicos, consulte as instruções para recebimento de links dinâmicos do Android.

Depois de receber o link conforme descrito acima, verifique se ele é destinado à autenticação por e-mail e conclua o login.

Java
Android

FirebaseAuth auth = FirebaseAuth.getInstance();
Intent intent = getIntent();
String emailLink = intent.getData().toString();

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    String email = "someemail@domain.com";

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                @Override
                public void onComplete(@NonNull Task<AuthResult> task) {
                    if (task.isSuccessful()) {
                        Log.d(TAG, "Successfully signed in with email link!");
                        AuthResult result = task.getResult();
                        // You can access the new user via result.getUser()
                        // Additional user info profile *not* available via:
                        // result.getAdditionalUserInfo().getProfile() == null
                        // You can check if the user is new or existing:
                        // result.getAdditionalUserInfo().isNewUser()
                    } else {
                        Log.e(TAG, "Error signing in with email link", task.getException());
                    }
                }
            });
}

Kotlin
Android

val auth = FirebaseAuth.getInstance()
val intent = intent
val emailLink = intent.data!!.toString()

// Confirm the link is a sign-in with email link.
if (auth.isSignInWithEmailLink(emailLink)) {
    // Retrieve this from wherever you stored it
    val email = "someemail@domain.com"

    // The client SDK will parse the code from the link for you.
    auth.signInWithEmailLink(email, emailLink)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "Successfully signed in with email link!")
                    val result = task.result
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error signing in with email link", task.exception)
                }
            }
}

Para saber mais sobre como processar o login com o link por e-mail em um aplicativo para iOS, consulte este guia.

Para saber mais sobre como processar o login com o link por e-mail em um aplicativo da Web, consulte este guia.

Também é possível vincular este método de autenticação a um usuário existente. Por exemplo, um usuário já autenticado com outro provedor, como número de telefone, pode incluir este método de login na conta dele.

A diferença está na segunda metade da operação:

Java
Android

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Link the credential to the current user.
auth.getCurrentUser().linkWithCredential(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    Log.d(TAG, "Successfully linked emailLink credential!");
                    AuthResult result = task.getResult();
                    // You can access the new user via result.getUser()
                    // Additional user info profile *not* available via:
                    // result.getAdditionalUserInfo().getProfile() == null
                    // You can check if the user is new or existing:
                    // result.getAdditionalUserInfo().isNewUser()
                } else {
                    Log.e(TAG, "Error linking emailLink credential", task.getException());
                }
            }
        });

Kotlin
Android

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Link the credential to the current user.
auth.currentUser!!.linkWithCredential(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                Log.d(TAG, "Successfully linked emailLink credential!")
                val result = task.result
                // You can access the new user via result.getUser()
                // Additional user info profile *not* available via:
                // result.getAdditionalUserInfo().getProfile() == null
                // You can check if the user is new or existing:
                // result.getAdditionalUserInfo().isNewUser()
            } else {
                Log.e(TAG, "Error linking emailLink credential", task.exception)
            }
        }

Também é possível usá-lo para reautenticar um usuário de link por e-mail antes de executar uma operação confidencial.

Java
Android

// Construct the email link credential from the current URL.
AuthCredential credential =
        EmailAuthProvider.getCredentialWithLink(email, emailLink);

// Re-authenticate the user with this credential.
auth.getCurrentUser().reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // User is now successfully reauthenticated
                } else {
                    Log.e(TAG, "Error reauthenticating", task.getException());
                }
            }
        });

Kotlin
Android

// Construct the email link credential from the current URL.
val credential = EmailAuthProvider.getCredentialWithLink(email, emailLink)

// Re-authenticate the user with this credential.
auth.currentUser!!.reauthenticateAndRetrieveData(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // User is now successfully reauthenticated
            } else {
                Log.e(TAG, "Error reauthenticating", task.exception)
            }
        }

No entanto, este fluxo pode não ser concluído, já que ele pode terminar em um dispositivo diferente do que o usado para fazer login. Nesse caso, é possível exibir um erro ao usuário para obrigá-lo a abrir o link no mesmo dispositivo. Você pode transmitir um estado no link para fornecer informações sobre o tipo de operação e o uid do usuário.

Caso ambos os logins por senha e por link de e-mail sejam compatíveis, use fetchSignInMethodsForEmail para diferenciar o método do usuário. Isso é útil nos fluxos que priorizam identificadores, em que o usuário é solicitado a fornecer o e-mail e precisa escolher o método de login:

Java
Android

auth.fetchSignInMethodsForEmail(email)
        .addOnCompleteListener(new OnCompleteListener<SignInMethodQueryResult>() {
            @Override
            public void onComplete(@NonNull Task<SignInMethodQueryResult> task) {
                if (task.isSuccessful()) {
                    SignInMethodQueryResult result = task.getResult();
                    List<String> signInMethods = result.getSignInMethods();
                    if (signInMethods.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                        // User can sign in with email/password
                    } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                        // User can sign in with email/link
                    }
                } else {
                    Log.e(TAG, "Error getting sign in methods for user", task.getException());
                }
            }
        });

Kotlin
Android

auth.fetchSignInMethodsForEmail(email)
        .addOnSuccessListener { result ->
            val signInMethods = result.signInMethods
            if (signInMethods!!.contains(EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD)) {
                // User can sign in with email/password
            } else if (signInMethods.contains(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD)) {
                // User can sign in with email/link
            }
        }
        .addOnFailureListener { exception ->
            Log.e(TAG, "Error getting sign in methods for user", exception)
        }

Conforme descrito acima, e-mail/senha e e-mail/link têm o mesmo EmailAuthProvider (PROVIDER_ID igual) com diferentes métodos de login.

Próximas etapas

Depois que um usuário faz login pela primeira vez, uma nova conta é criada e vinculada às credenciais, que podem ser o número do telefone, o nome de usuário e a senha ou as informações do provedor de autenticação. Essa nova conta é armazenada como parte do projeto do Firebase e pode ser usada para identificar um usuário em todos os apps do projeto, seja qual for o método de login utilizado.

  • Nos apps, é possível acessar informações básicas de perfil do usuário por meio do objeto FirebaseUser. Consulte Gerenciar usuários.

  • Nas Regras de segurança do Firebase Realtime Database e do Cloud Storage, é possível usar a variável auth para encontrar o código exclusivo do usuário conectado. Use essa informação para controlar o acesso dele aos dados.

Os usuários podem fazer login no app usando vários provedores de autenticação. Basta vincular as credenciais desses provedores a uma conta de usuário.

Para desconectar um usuário, chame signOut:

Java
Android

FirebaseAuth.getInstance().signOut();

Kotlin
Android

FirebaseAuth.getInstance().signOut()