Autenticar usando a Microsoft em plataformas Apple

Permita que os usuários se autentiquem com o Firebase usando provedores OAuth, como o Microsoft Azure Active Directory. Basta integrar o login genérico do OAuth baseado na Web ao seu app usando o SDK do Firebase para realizar o fluxo de login completo.

Antes de começar

Para fazer login de usuários usando contas da Microsoft (Azure Active Directory e contas pessoais da Microsoft), primeiro ative a Microsoft como um provedor de login do seu projeto do Firebase:

  1. Adicione o Firebase ao projeto da Apple.
  2. No console do Firebase, abra a seção Auth.
  3. Na guia Método de login, ative o provedor Microsoft.
  4. Adicione o ID do cliente e a Chave secreta do cliente do console do desenvolvedor às configurações do provedor:
    1. Para registrar um cliente OAuth da Microsoft, siga as instruções em Guia de início rápido: como registrar um app com o endpoint do Azure Active Directory v2.0. Observe que esse endpoint oferece suporte para o login de contas pessoais da Microsoft, bem como de contas do Azure Active Directory. Saiba mais sobre o Azure Active Directory v2.0.
    2. Ao registrar apps nesses provedores, registre o domínio *.firebaseapp.com do projeto como o domínio de redirecionamento do seu app.
  5. Clique em Salvar.

Processar o fluxo de login com o SDK do Firebase

Para processar o fluxo de login com o SDK do Firebase para plataformas Apple, siga estas etapas:

  1. Adicione esquemas de URL personalizado ao seu projeto do Xcode:

    1. Abra a configuração do seu projeto clicando duas vezes no nome dele na visualização em árvore à esquerda. Selecione seu app na seção DESTINOS. Em seguida, selecione a guia Informações e expanda a seção Tipos de URL.
    2. Clique no botão + e adicione o ID do app codificado como um esquema de URL. Encontre o ID codificado do app na página Configurações gerais do Console do Firebase na seção do seu app iOS. Deixe os outros campos em branco.

      Quando concluída, a configuração será semelhante à mostrada a seguir, mas com os valores específicos do seu app:

      Captura de tela da interface de configuração do esquema de URL personalizado do Xcode
  2. Crie uma instância de um OAuthProvider usando o ID do provedor microsoft.com.

        var provider = OAuthProvider(providerID: "microsoft.com")
        
        FIROAuthProvider *provider = [FIROAuthProvider providerWithProviderID:@"microsoft.com"];
        
  3. Opcional: especifique os parâmetros OAuth personalizados que você quer enviar com a solicitação OAuth.

        provider.customParameters = [
          "prompt": "consent",
          "login_hint": "user@firstadd.onmicrosoft.com"
        ]
        
        [provider setCustomParameters:@{@"prompt": @"consent", @"login_hint": @"user@firstadd.onmicrosoft.com"}];
        

    Para saber quais parâmetros são aceitos pela Microsoft, consulte a documentação do OAuth da Microsoft. Não é possível transmitir os parâmetros exigidos pelo Firebase com setCustomParameters. Esses parâmetros são client_id, response_type, redirect_uri, state, scope e response_mode.

    Para permitir que apenas usuários de um determinado locatário do Azure AD façam login no aplicativo, é possível usar o nome de domínio do locatário do Azure AD ou o identificador GUID do locatário. Isso pode ser feito ao especificar o campo "locatário" no objeto de parâmetros personalizados.

        provider.customParameters = [
          // Optional "tenant" parameter in case you are using an Azure AD
          // tenant. eg. '8eaef023-2b34-4da1-9baa-8bc8c9d6a490' or
          // 'contoso.onmicrosoft.com' or "common" for tenant-independent
          // tokens. The default value is "common".
          "tenant": "TENANT_ID"
        ]
        
        // Optional "tenant" parameter in case you are using an Azure AD tenant.
        // eg. '8eaef023-2b34-4da1-9baa-8bc8c9d6a490' or
        // 'contoso.onmicrosoft.com' or "common" for tenant-independent tokens.
        // The default value is "common".
        provider.customParameters = @{@"tenant": @"TENANT_ID"};
        
  4. Opcional: especifique os outros escopos de OAuth 2.0 além do perfil básico que você quer solicitar ao provedor de autenticação.

        provider.scopes = ["mail.read", "calendars.read"]
        
        [provider setScopes:@[@"mail.read", @"calendars.read"]];
        

    Para saber mais, consulte a documentação de permissões e consentimento da Microsoft.

  5. Opcional: se quiser personalizar a forma como o app apresenta o SFSafariViewController ou o UIWebView ao exibir o reCAPTCHA para o usuário, crie uma classe personalizada que esteja em conformidade com o protocolo AuthUIDelegate e transmita-a para credentialWithUIDelegate.

  6. Use o objeto de provedor do OAuth para a autenticação no Firebase.

        // Replace nil with the custom class that conforms to AuthUIDelegate
        // you created in last step to use a customized web view.
        provider.getCredentialWith(nil) { credential, error in
          if error != nil {
            // Handle error.
          }
          if credential != nil {
            Auth().signIn(with: credential) { authResult, error in
              if error != nil {
                // Handle error.
              }
              // User is signed in.
              // IdP data available in authResult.additionalUserInfo.profile.
              // OAuth access token can also be retrieved:
              // (authResult.credential as? OAuthCredential)?.accessToken
              // OAuth ID token can also be retrieved:
              // (authResult.credential as? OAuthCredential)?.idToken
            }
          }
        }
        
        [provider getCredentialWithUIDelegate:nil
                                   completion:^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
          if (error) {
           // Handle error.
          }
          if (credential) {
            [[FIRAuth auth] signInWithCredential:credential
                                      completion:^(FIRAuthDataResult *_Nullable authResult, NSError *_Nullable error) {
              if (error) {
                // Handle error.
              }
              // User is signed in.
              // IdP data available in authResult.additionalUserInfo.profile.
              // OAuth access token can also be retrieved:
              // ((FIROAuthCredential *)authResult.credential).accessToken
              // OAuth ID token can also be retrieved:
              // ((FIROAuthCredential *)authResult.credential).idToken
            }];
          }
        }];
        

    Com o token de acesso OAuth, é possível chamar a API Microsoft Graph.

    Por exemplo, para receber informações básicas de perfil, chame a API REST transmitindo o token de acesso no cabeçalho Authorization:

    https://graph.microsoft.com/v1.0/me

    Ao contrário de outros provedores suportados pelo Firebase Auth, a Microsoft não fornece um URL de foto. Em vez disso, os dados binários de uma foto de perfil precisam ser solicitados usando a API Microsoft Graph.

    Além do token de acesso OAuth, é possível usar o objeto OAuthCredential para recuperar o token de ID OAuth do usuário. A declaração sub no token de ID é específica do app e não vai corresponder ao identificador federado de usuários, que é usado pelo Firebase Auth e pode ser acessado utilizando user.providerData[0].uid. Nesse caso, o campo de declaração oid deve ser utilizado. Ao usar um locatário do Azure AD para fazer login, a declaração oid será uma correspondência exata. No entanto, para o caso sem locatário, o campo oid será preenchido. Para um ID federado 4b2eabcdefghijkl, oid terá um formulário 00000000-0000-0000-4b2e-abcdefghijkl.

  7. Os exemplos acima se concentram nos fluxos de login, mas também é possível vincular um provedor da Microsoft a um usuário atual usando linkWithCredential. Por exemplo, é possível vincular vários provedores ao mesmo usuário, o que permite que ele faça login usando qualquer um deles.

        Auth().currentUser.link(withCredential: credential) { authResult, error in
          if error != nil {
            // Handle error.
          }
          // Microsoft credential is linked to the current user.
          // IdP data available in authResult.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.accessToken
          // OAuth ID token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.idToken
        }
        
        [[FIRAuth auth].currentUser
            linkWithCredential:credential
                    completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
          if (error) {
            // Handle error.
          }
          // Microsoft credential is linked to the current user.
          // IdP data available in authResult.additionalUserInfo.profile.
          // OAuth access token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).accessToken
          // OAuth ID token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).idToken
        }];
        
  8. É possível usar o mesmo padrão com reauthenticateWithCredential, que pode ser utilizado para recuperar credenciais novas de operações confidenciais que exigem um login recente.

        Auth().currentUser.reauthenticateWithCredential(withCredential: credential) { authResult, error in
          if error != nil {
            // Handle error.
          }
          // User is re-authenticated with fresh tokens minted and
          // should be able to perform sensitive operations like account
          // deletion and email or password update.
          // IdP data available in result.additionalUserInfo.profile.
          // Additional OAuth access token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.accessToken
          // OAuth ID token can also be retrieved:
          // (authResult.credential as? OAuthCredential)?.idToken
        }
        
        [[FIRAuth auth].currentUser
            reauthenticateWithCredential:credential
                              completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
          if (error) {
            // Handle error.
          }
          // User is re-authenticated with fresh tokens minted and
          // should be able to perform sensitive operations like account
          // deletion and email or password update.
          // IdP data available in result.additionalUserInfo.profile.
          // Additional OAuth access token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).accessToken
          // OAuth ID token can also be retrieved:
          // ((FIROAuthCredential *)authResult.credential).idToken
        }];
        

Se você ativou a configuração Uma conta por endereço de e-mail no Console do Firebase, quando um usuário tentar se conectar a um provedor (como a Microsoft) com um e-mail que já existe em outro provedor de usuário do Firebase (como o Google), o erro FIRAuthErrorCodeAccountExistsWithDifferentCredential será exibido com um objeto FIRAuthCredential temporário (credencial da Microsoft). Para concluir o login no provedor pretendido, o usuário primeiro precisa fazer login no provedor atual (Google) e depois vinculá-lo ao FIRAuthCredential anterior (credencial da Microsoft). O resultado desse processo seria semelhante ao mostrado abaixo:

  // Sign-in with an OAuth credential.
  provider.getCredentialWith(nil) { credential, error in
    // An account with the same email already exists.
    if (error as NSError?)?.code == AuthErrorCode.accountExistsWithDifferentCredential.rawValue {
      // Get pending credential and email of existing account.
      let existingAcctEmail = (error! as NSError).userInfo[AuthErrorUserInfoEmailKey] as! String
      let pendingCred = (error! as NSError).userInfo[AuthErrorUserInfoUpdatedCredentialKey] as! AuthCredential
      // Lookup existing account identifier by the email.
      Auth.auth().fetchProviders(forEmail:existingAcctEmail) { providers, error in
        // Existing email/password account.
        if (providers?.contains(EmailAuthProviderID))! {
          // Existing password account for email. Ask user to provide the password of the
          // existing account.
          // Sign in with existing account.
          Auth.auth().signIn(withEmail:existingAcctEmail, password:password) { user, error in
            // Successfully signed in.
            if user != nil {
              // Link pending credential to account.
              Auth.auth().currentUser?.linkAndRetrieveData(with: pendingCred) { result, error in
                // ...
              }
            }
          }
        }
      }
      return
    }

    // Other errors.
    if error != nil {
      // handle the error.
      return
    }

    // Sign in with the credential.
    if credential != nil {
      Auth.auth().signInAndRetrieveData(with: credential!) { result, error in
        if error != nil {
          // handle the error.
          return
        }
      }
    }
  }

  
  // Sign-in with an OAuth credential.
  [provider getCredentialWithUIDelegate:nil
                             completion:^(FIRAuthCredential *_Nullable credential, NSError *_Nullable error) {
    // An account with the same email already exists.
    if (error.code == FIRAuthErrorCodeAccountExistsWithDifferentCredential) {
      // Get pending credential and email of existing account.
      NSString *existingAcctEmail = error.userInfo[FIRAuthErrorUserInfoEmailKey];
      FIRAuthCredential *pendingCred = error.userInfo[FIRAuthErrorUserInfoUpdatedCredentialKey];
      // Lookup existing account identifier by the email.
      [[FIRAuth auth] fetchProvidersForEmail:existingAcctEmail
                                 completion:^(NSArray<NSString *> *_Nullable providers,
                                              NSError *_Nullable error) {
        // Existing email/password account.
        if ( [providers containsObject:FIREmailAuthProviderID] ) {
          // Existing password account for email. Ask user to provide the password of the
          // existing account.

          // Sign in with existing account.
          [[FIRAuth auth] signInWithEmail:existingAcctEmail
                                 password:password
                               completion:^(FIRUser *user, NSError *error) {
            // Successfully signed in.
            if (user) {
              // Link pending credential to account.
              [[FIRAuth auth].currentUser linkWithCredential:pendingCred
                                                  completion:^(FIRUser *_Nullable user,
                                                               NSError *_Nullable error) {
                // ...
              }];
            }
          }];
        }
      }];
      return;
    }

    // Other errors.
    if (error) {
      // handle the error.
      return;
    }

    // Sign in with the credential.
    if (credential) {
      [[FIRAuth auth] signInAndRetrieveDataWithCredential:credential
          completion:^(FIRAuthDataResult *_Nullable authResult,
                       NSError *_Nullable error) {
        if (error) {
          // handle the error.
          return;
        }
      }];
    }
  }];
  

Ao contrário de outros provedores OAuth aceitos pelo Firebase, como Google, Facebook e Twitter, em que é possível fazer login diretamente com credenciais baseadas em token de acesso OAuth, isso não é possível no Firebase Auth ao usar provedores como a Microsoft porque o servidor do Firebase Auth não consegue verificar o público dos tokens de acesso OAuth da Microsoft. Esse é um requisito de segurança crítico e pode expor aplicativos e sites a ataques de repetição em que um token de acesso OAuth da Microsoft recebido em um projeto (invasor) pode ser usado para acessar outro projeto (vítima). Em vez disso, o Firebase Auth permite gerenciar todo o fluxo do OAuth e trocar o código de autorização usando o ID do cliente e o secret do OAuth configurados no Console do Firebase. Um código de autorização recebido em um projeto não pode ser usado em outro, porque só pode ser utilizado em conjunto com um ID do cliente/secret específicos.

Se for preciso usar esses provedores em ambientes sem suporte, será necessário usar uma biblioteca OAuth de terceiros e uma autenticação personalizada do Firebase. O primeiro é necessário para autenticar com o provedor, e o segundo para trocar a credencial do provedor por um token personalizado.

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.

  • É possível receber as informações básicas de perfil do usuário do objeto User nos seus apps. Consulte Gerenciar usuários.

  • Nas Regras de segurança Firebase Realtime Database e Cloud Storage, você pode acessar o ID exclusivo do usuário conectado pela variável auth e usar essas informações para controlar quais dados um usuário pode acessar.

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:.

let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print("Error signing out: %@", signOutError)
}
NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

Adicione também o código de tratamento de erros para todo o intervalo de erros de autenticação. Consulte Tratamento de erros.