Autenticar usando a Apple com JavaScript

Você pode usar o SDK do Firebase para permitir que os usuários façam a autenticação com o Firebase usando o ID Apple para realizar todo o fluxo de login do OAuth 2.0.

Antes de começar

Para fazer login de usuários usando a Apple, primeiro configure o recurso Iniciar sessão com a Apple no site do desenvolvedor da Apple e ative-a como um provedor de login para seu projeto do Firebase.

Participe do Programa para desenvolvedores da Apple

O recurso Iniciar sessão com a Apple só pode ser configurado por membros do Programa para desenvolvedores da Apple.

Configurar o recurso "Iniciar sessão com a Apple"

No site do Desenvolvedor da Apple, faça o seguinte:

  1. Associe seu site ao seu aplicativo conforme descrito na primeira seção de Configurar Login com a Apple para a Web. Quando solicitado, registre o URL a seguir como um URL de retorno:

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

    Você pode acessar o ID do projeto do Firebase na página de configurações do Console do Firebase.

    Quando terminar, anote o novo ID de serviço, que será necessário na próxima seção.

  2. Crie uma chave privada de Início de sessão com a Apple. Você precisará da sua nova chave privada e do ID da chave na próxima seção.
  3. Se você usar qualquer um dos recursos do Firebase Authentication que enviam e-mails para os usuários, incluindo login com link por e-mail, verificação de endereço de e-mail, revogação de alteração na conta e outros, configure o serviço de redirecionamento de e-mail privado da Apple e registre noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com ou seu domínio de modelo de e-mail personalizado para que a Apple possa redirecionar os e-mails enviados pelo Firebase Authentication para endereços anônimos de e-mails da Apple.

Ativar a Apple como um provedor de login

  1. Adicione o Firebase ao seu projeto.
  2. No Console do Firebase, abra a seção Auth. Na guia Método de login, ative o provedor Apple. Especifique o ID do serviço que você criou na seção anterior. Além disso, na seção de configuração do fluxo de código do OAuth, especifique o ID de equipe da Apple, a chave privada e o ID da chave que você criou na seção anterior.

Atenda os requisitos de dados anônimos da Apple

O recurso Iniciar sessão com a Apple permite que os usuários decidam se querem que seus dados fiquem anônimos, incluindo o endereço de e-mail, ao fazer login. Os usuários que escolhem essa opção têm endereços de e-mail com o domínio privaterelay.appleid.com. Ao usar o recurso Iniciar sessão com a Apple no seu aplicativo, você precisa estar em conformidade com todos os termos ou políticas do desenvolvedor aplicáveis da Apple relacionados a esses IDs anônimos da Apple.

Isso inclui obter o consentimento do usuário exigido antes de associar qualquer informação pessoal de identificação direta a um ID anônimo da Apple. O uso do Firebase Authentication pode incluir as seguintes ações:

  • Vincular um endereço de e-mail a um ID Apple anonimizado ou vice-versa.
  • Vincular um número de telefone a um ID Apple anonimizado ou vice-versa.
  • Vincular uma credencial social não anônima (Facebook, Google etc.) a um ID Apple anonimizado ou vice-versa.

Essa não é uma lista completa. Consulte o contrato de licença do programa para desenvolvedores da Apple na seção de associação da sua conta de desenvolvedor para verificar se o app atende aos requisitos da Apple.

Processar o fluxo de login com o SDK do Firebase

Se você estiver criando um app da Web, a maneira mais fácil de autenticar seus usuários com o Firebase usando contas da Apple é gerenciar todo o fluxo de login com o SDK do Firebase para JavaScript.

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

  1. Crie uma instância de um OAuthProvider usando o ID de provedor apple.com correspondente.

    API modular da Web

    import { OAuthProvider } from "firebase/auth";
    
    const provider = new OAuthProvider('apple.com');

    API com namespace da Web

    var provider = new firebase.auth.OAuthProvider('apple.com');
  2. Opcional: especifique escopos adicionais do OAuth 2.0 além do padrão que você quer solicitar ao provedor de autenticação.

    API modular da Web

    provider.addScope('email');
    provider.addScope('name');

    API com namespace da Web

    provider.addScope('email');
    provider.addScope('name');

    Por padrão, quando a opção Uma conta por endereço de e-mail é ativada, o Firebase solicita escopos de nome e e-mail. Se você mudar essa configuração para Várias contas por endereço de e-mail, o Firebase não solicitará nenhum escopo da Apple, a não ser que você os especifique.

  3. Opcional: se você quiser mostrar a tela de login da Apple em um idioma diferente do inglês, configure o parâmetro locale. Consulte Fazer login com os documentos da Apple para ver as localidades compatíveis.

    API modular da Web

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });

    API com namespace da Web

    provider.setCustomParameters({
      // Localize the Apple authentication screen in French.
      locale: 'fr'
    });
  4. Use o objeto de provedor do OAuth para a autenticação no Firebase. Você pode solicitar que os usuários façam login com as respectivas contas da Apple abrindo uma janela pop-up ou redirecionando para a página de login. O método de redirecionamento é recomendável para dispositivos móveis.

    • Para fazer login com uma janela pop-up, chame signInWithPopup():

      API modular da Web

      import { getAuth, signInWithPopup, OAuthProvider } from "firebase/auth";
      
      const auth = getAuth();
      signInWithPopup(auth, provider)
        .then((result) => {
          // The signed-in user info.
          const user = result.user;
      
          // Apple credential
          const credential = OAuthProvider.credentialFromResult(result);
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
          // ...
        })
        .catch((error) => {
          // Handle Errors here.
          const errorCode = error.code;
          const errorMessage = error.message;
          // The email of the user's account used.
          const email = error.customData.email;
          // The credential that was used.
          const credential = OAuthProvider.credentialFromError(error);
      
          // ...
        });

      API com namespace da Web

      firebase
        .auth()
        .signInWithPopup(provider)
        .then((result) => {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
      
          // The signed-in user info.
          var user = result.user;
      
          // You can also get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
      
          // IdP data available using getAdditionalUserInfo(result)
        // ...
        })
        .catch((error) => {
          // Handle Errors here.
          var errorCode = error.code;
          var errorMessage = error.message;
          // The email of the user's account used.
          var email = error.email;
          // The firebase.auth.AuthCredential type that was used.
          var credential = error.credential;
      
          // ...
        });
    • Para redirecionar os usuários à página de login, chame signInWithRedirect():

    Siga as práticas recomendadas ao usar signInWithRedirect, linkWithRedirect ou reauthenticateWithRedirect.

    API modular da Web

    import { getAuth, signInWithRedirect } from "firebase/auth";
    
    const auth = getAuth();
    signInWithRedirect(auth, provider);

    API com namespace da Web

    firebase.auth().signInWithRedirect(provider);

    Depois que o usuário fizer login e retornar à página, chame getRedirectResult() para saber o resultado do login.

    API modular da Web

    import { getAuth, getRedirectResult, OAuthProvider } from "firebase/auth";
    
    // Result from Redirect auth flow.
    const auth = getAuth();
    getRedirectResult(auth)
      .then((result) => {
        const credential = OAuthProvider.credentialFromResult(result);
        if (credential) {
          // You can also get the Apple OAuth Access and ID Tokens.
          const accessToken = credential.accessToken;
          const idToken = credential.idToken;
        }
        // The signed-in user info.
        const user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        const errorCode = error.code;
        const errorMessage = error.message;
        // The email of the user's account used.
        const email = error.customData.email;
        // The credential that was used.
        const credential = OAuthProvider.credentialFromError(error);
    
        // ...
      });

    API com namespace da Web

    // Result from Redirect auth flow.
    firebase
      .auth()
      .getRedirectResult()
      .then((result) => {
        if (result.credential) {
          /** @type {firebase.auth.OAuthCredential} */
          var credential = result.credential;
    
          // You can get the Apple OAuth Access and ID Tokens.
          var accessToken = credential.accessToken;
          var idToken = credential.idToken;
    
          // IdP data available in result.additionalUserInfo.profile.
          // ...
        }
        // The signed-in user info.
        var user = result.user;
      })
      .catch((error) => {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
    
        // ...
      });

    Também é aqui que você identifica e corrige erros. Para conferir uma lista de códigos de erro, consulte a Referência da API.

    Diferentemente de outros provedores que recebem suporte do Firebase Auth, a Apple não fornece um URL de foto.

    Além disso, quando o usuário opta por não compartilhar o e-mail com o app, a Apple fornece um endereço de e-mail exclusivo para esse usuário, no formato xyz@privaterelay.appleid.com, que é compartilhado com seu app. Se você tiver configurado o serviço de redirecionamento de e-mail privado, a Apple encaminhará os e-mails enviados ao endereço anonimizado para o endereço de e-mail real do usuário.

    A Apple só compartilha informações do usuário, como o nome de exibição, com apps na primeira vez que um usuário faz login. Normalmente, o Firebase armazena o nome de exibição na primeira vez que um usuário faz login com a Apple. Ele pode ser obtido com firebase.auth().currentUser.displayName. No entanto, se você já usou a Apple para fazer login de um usuário no app sem usar o Firebase, a Apple não fornecerá ao Firebase o nome de exibição do usuário.

Reautenticação e vinculação de contas

O mesmo padrão pode ser usado com reauthenticateWithPopup() e reauthenticateWithRedirect(), que você pode usar para recuperar uma nova credencial para operações confidenciais que exigem login recente:

API modular da Web

import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";

// Result from Redirect auth flow.
const auth = getAuth();
const provider = new OAuthProvider('apple.com');

reauthenticateWithPopup(auth.currentUser, provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.

    // The signed-in user info.
    const user = result.user;

    // You can also get the Apple OAuth Access and ID Tokens.
    const credential = OAuthProvider.credentialFromResult(result);
    const accessToken = credential.accessToken;
    const idToken = credential.idToken;

    // ...
  })
  .catch((error) => {
    // Handle Errors here.
    const errorCode = error.code;
    const errorMessage = error.message;
    // The email of the user's account used.
    const email = error.customData.email;
    // The credential that was used.
    const credential = OAuthProvider.credentialFromError(error);

    // ...
  });

API com namespace da Web

const provider = new firebase.auth.OAuthProvider('apple.com');

firebase
  .auth()
  .currentUser
  .reauthenticateWithPopup(provider)
  .then((result) => {
    // User is re-authenticated with fresh tokens minted and can perform
    // sensitive operations like account deletion, or updating their email
    // address or password.
    /** @type {firebase.auth.OAuthCredential} */
    var credential = result.credential;

    // The signed-in user info.
    var user = result.user;
     // You can also get the Apple OAuth Access and ID Tokens.
    var accessToken = credential.accessToken;
    var idToken = credential.idToken;

    // IdP data available in result.additionalUserInfo.profile.
      // ...
  })
  .catch((error) => {
    // Handle Errors here.
    var errorCode = error.code;
    var errorMessage = error.message;
    // The email of the user's account used.
    var email = error.email;
    // The firebase.auth.AuthCredential type that was used.
    var credential = error.credential;

    // ...
  });

Além disso, você pode usar linkWithPopup() e linkWithRedirect() para vincular diferentes provedores de identidade a contas existentes.

Observe que a Apple exige que você receba o consentimento explícito dos usuários antes de vincular as contas da Apple a outros dados.

Por exemplo, para vincular uma conta do Facebook à conta atual do Firebase, use o token de acesso recebido ao iniciar a sessão do usuário no Facebook:

API modular da Web

import { getAuth, linkWithPopup, FacebookAuthProvider } from "firebase/auth";

const auth = getAuth();
const provider = new FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
linkWithPopup(auth.currentUser, provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // ...

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

API com namespace da Web

const provider = new firebase.auth.FacebookAuthProvider();
provider.addScope('user_birthday');

// Assuming the current user is an Apple user linking a Facebook provider.
firebase.auth().currentUser.linkWithPopup(provider)
    .then((result) => {
      // Facebook credential is linked to the current Apple user.
      // Facebook additional data available in result.additionalUserInfo.profile,

      // Additional Facebook OAuth access token can also be retrieved.
      // result.credential.accessToken

      // The user can now sign in to the same account
      // with either Apple or Facebook.
    })
    .catch((error) => {
      // Handle error.
    });

Autenticar com Firebase em uma extensão do Chrome

Se você está criando um app de extensão do Chrome, é necessário adicionar o ID da extensão:

  1. Abra seu projeto no Console do Firebase.
  2. Na seção Autenticação, abra a página Método de login.
  3. Adicione um URI como o seguinte à lista de domínios autorizados:
    chrome-extension://CHROME_EXTENSION_ID

Somente as operações pop-up (signInWithPopup, linkWithPopup e reauthenticateWithPopup) estão disponíveis para as extensões do Chrome. Isso ocorre porque as extensões não podem usar redirecionamentos HTTP. Chame esses métodos usando um script de página em segundo plano porque, se usar o pop-up de ação do navegador, ele será cancelado pelo pop-up de autenticação. Os métodos pop-up só podem ser usados em extensões que usam o Manifest V2. O Manifest V3 mais recente só permite scripts em segundo plano na forma de service workers, que não podem realizar as operações pop-up.

No arquivo de manifesto da sua extensão do Chrome, adicione o URL https://apis.google.com à lista de permissões content_security_policy.

Observe que você ainda precisa verificar o domínio personalizado com a Apple de forma semelhante ao domínio padrão firebaseapp.com:

http://auth.custom.example.com/.well-known/apple-developer-domain-association.txt

Avançado: autenticar com o Firebase em Node.js

Para autenticar com o Firebase em um aplicativo Node.js:

  1. Faça o login do usuário com a conta da Apple e receba o token do ID da Apple do usuário. Isso pode ser feito de várias maneiras. Por exemplo, se seu app Node.js tiver um front-end de navegador:

    1. No seu back-end, gere uma string aleatória ("nonce") e calcule o hash SHA256 dela. O nonce é um valor de uso único utilizado para validar uma única ida e volta entre o seu back-end e os servidores de autenticação da Apple.

      API modular da Web

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = (length) => {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        let nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');

      API com namespace da Web

      const crypto = require("crypto");
      const string_decoder = require("string_decoder");
      
      // Generate a new random string for each sign-in
      const generateNonce = function(length) {
        const decoder = new string_decoder.StringDecoder("ascii");
        const buf = Buffer.alloc(length);
        var nonce = "";
        while (nonce.length < length) {
          crypto.randomFillSync(buf);
          nonce = decoder.write(buf);
        }
        return nonce.slice(0, length);
      };
      
      const unhashedNonce = generateNonce(10);
      
      // SHA256-hashed nonce in hex
      const hashedNonceHex = crypto.createHash('sha256')
        .update(unhashedNonce).digest().toString('hex');
    2. Na página de login, especifique o nonce com hash na configuração "Iniciar sessão com a Apple":

      <script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
      <div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
      <script>
          AppleID.auth.init({
              clientId: YOUR_APPLE_CLIENT_ID,
              scope: 'name email',
              redirectURI: URL_TO_YOUR_REDIRECT_HANDLER,  // See the next step.
              state: '[STATE]',  // Optional value that Apple will send back to you
                                 // so you can return users to the same context after
                                 // they sign in.
              nonce: HASHED_NONCE  // The hashed nonce you generated in the previous step.
          });
      </script>
      
    3. Receba o token do ID da Apple da resposta do POSTed auth no servidor:

      app.post('/redirect', (req, res) => {
        const savedState = req.cookies.__session;
        const code = req.body.code;
        const state = req.body.state;
        const appleIdToken = req.body.id_token;
        if (savedState !== state || !code) {
          res.status(403).send('403: Permission denied');
        } else {
          // Sign in with Firebase using appleIdToken. (See next step).
        }
      });
      

    Consulte também Como configurar sua página da Web para fazer login com a Apple.

  2. Depois de receber o token do ID da Apple do usuário, use-o para criar um objeto Credential e, em seguida, faça o login do usuário com a credencial:

    API modular da Web

    import { getAuth, signInWithCredential, OAuthProvider } from "firebase/auth";
    
    const auth = getAuth();
    
    // Build Firebase credential with the Apple ID token.
    const provider = new OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    signInWithCredential(auth, authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

    API com namespace da Web

    // Build Firebase credential with the Apple ID token.
    const provider = new firebase.auth.OAuthProvider('apple.com');
    const authCredential = provider.credential({
      idToken: appleIdToken,
      rawNonce: unhashedNonce,
    });
    
    // Sign in with credential form the Apple user.
    firebase.auth().signInWithCredential(authCredential)
      .then((result) => {
        // User signed in.
      })
      .catch((error) => {
        // An error occurred. If error.code == 'auth/missing-or-invalid-nonce',
        // make sure you're sending the SHA256-hashed nonce as a hex string
        // with your request to Apple.
        console.log(error);
      });

Próximas etapas

Depois que um usuário faz login pela primeira vez, uma nova conta de usuário é 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, a maneira recomendada de saber o status de autenticação do seu usuário é definindo um observador no objeto Auth. É possível, então, receber as informações básicas de perfil do usuário do objeto User. Consulte Gerenciar usuários.

  • Nas Regras de segurança do Firebase Realtime Database e do Cloud Storage, é possível receber o ID exclusivo do usuário conectado da variável auth e usar esse ID para controlar quais dados uma pessoa 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:

API modular da Web

import { getAuth, signOut } from "firebase/auth";

const auth = getAuth();
signOut(auth).then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});

API com namespace da Web

firebase.auth().signOut().then(() => {
  // Sign-out successful.
}).catch((error) => {
  // An error happened.
});