Práticas recomendadas para usar o signInWithRedirect em navegadores que bloqueiam o acesso ao armazenamento de terceiros

Neste documento, descrevemos as práticas recomendadas para usar logins de redirecionamento nos navegadores que bloqueiam cookies de terceiros. Você precisa seguir uma das opções listadas aqui para que signInWithRedirect() funcione como esperado nos ambientes de produção em todos os navegadores.

Informações gerais

Para tornar o fluxo do signInWithRedirect() simples para você e seus usuários, o SDK do Firebase Authentication para JavaScript usa um iframe de origem cruzada que se conecta ao domínio do Firebase Hosting do seu app. No entanto, esse mecanismo não funciona com navegadores que bloqueiam o acesso ao armazenamento de terceiros.

Pedir aos usuários para desativar os recursos de particionamento de armazenamento no navegador raramente é possível. Como alternativa, implemente uma das seguintes opções de configuração no app, dependendo das especificações do caso de uso.

  • Se você hospeda o app com o Firebase Hosting em um subdomínio de firebaseapp.com, esse problema não afeta você, e não é preciso fazer nada.
  • Se você hospeda seu app com o Firebase Hosting em um domínio personalizado ou em um subdomínio de web.app, use a Opção 1.
  • Se você hospeda o app com um serviço que não é o Firebase, use a Opção 2, 3, 4 ou 5.

Opção 1: atualizar a configuração do Firebase para usar o domínio personalizado como o authDomain

Se você estiver hospedando seu app com o Firebase Hosting usando um domínio personalizado, configure o SDK do Firebase para usar seu domínio personalizado como o authDomain. Isso garante que o app e o iframe de autenticação usem o mesmo domínio, o que impede o problema de login. Se você não usa o Firebase Hosting, é preciso usar uma opção diferente.

Para atualizar sua configuração do Firebase e usar seu domínio personalizado como domínio de autenticação, faça o seguinte:

  1. Configure o SDK do Firebase para JavaScript para usar seu domínio personalizado como authDomain:

    const firebaseConfig = {
      apiKey: "<api-key>",
      authDomain: "<the-domain-that-serves-your-app>",
      databaseURL: "<database-url>",
      projectId: "<project-id>",
      appId: "<app-id>"
    };
    
  2. Adicione o novo authDomain à lista de URIs de redirecionamento autorizados do provedor OAuth. O modo de fazer isso depende do provedor, mas, em geral, você pode seguir a seção "Antes de começar" em qualquer provedor para obter instruções exatas (por exemplo, o provedor do Facebook). O URI atualizado para autorização é semelhante a https://<the-domain-that-serves-your-app>/__/auth/handler, e /__/auth/handler no final é importante.

    Da mesma forma, se você estiver usando um provedor SAML, adicione o novo authDomain ao URL do serviço de declaração de consumidor (ACS) SAML.

Opção 2: alternar para signInWithPopup()

Use signInWithPopup() em vez de signInWithRedirect(). O restante do código do app continua o mesmo, mas a recuperação do objeto UserCredential é diferente.

API modular da Web

  // Before
  // ==============
  signInWithRedirect(auth, new GoogleAuthProvider());
  // After the page redirects back
  const userCred = await getRedirectResult(auth);

  // After
  // ==============
  const userCred = await signInWithPopup(auth, new GoogleAuthProvider());

API com namespace da Web

  // Before
  // ==============
  firebase.auth().signInWithRedirect(new firebase.auth.GoogleAuthProvider());
  // After the page redirects back
  var userCred = await firebase.auth().getRedirectResult();

  // After
  // ==============
  var userCred = await firebase.auth().signInWithPopup(
      new firebase.auth.GoogleAuthProvider());
```

O login pop-up nem sempre é o ideal para usuários. Às vezes, os pop-ups são bloqueados pelo dispositivo ou plataforma, e o fluxo é menos estável para os usuários de dispositivos móveis. Se o uso de pop-ups for um problema para o app, aplique outra opção.

Opção 3: solicitações de autenticação de proxy para firebaseapp.com

O fluxo de signInWithRedirect começa redirecionando o domínio do app para o domínio especificado no parâmetro authDomain, na configuração do Firebase (".firebaseapp.com" por padrão). authDomain hospeda o código auxiliar de login que redireciona para o provedor de identidade, que, se não houver nenhum problema, redireciona para o domínio do app.

Quando o fluxo de autenticação retorna ao domínio do app, obtém-se acesso ao armazenamento do navegador do domínio auxiliar de login. Essa opção e a seguinte (para auto-hospedar o código) mitigam o acesso ao armazenamento de origem cruzada, que, de outra forma, é bloqueado pelos navegadores.

  1. Configure um proxy reverso no servidor do app para que as solicitações GET/POST para https://<app domain>/__/auth/ sejam encaminhadas para https://<project>.firebaseapp.com/__/auth/. Confirme se o encaminhamento é explícito para o navegador (isso não pode ser feito por meio de um redirecionamento 302).

    Se você usa o nginx para exibir seu domínio personalizado, a configuração de proxy reverso será como o exemplo abaixo:

    # reverse proxy for signin-helpers for popup/redirect sign in.
    location /__/auth {
      proxy_pass https://<project>.firebaseapp.com;
    }
    
  2. Siga as etapas da Opção 1 para atualizar o redirect_uri, o URL do ACS e o authDomain autorizados. Depois de implantar novamente o app, não haverá mais o acesso ao armazenamento de origem cruzada.

Opção 4: auto-hospedar o código auxiliar de login no domínio

Outra forma de eliminar o acesso ao armazenamento de origem cruzada é auto-hospedar o código auxiliar de login do Firebase. No entanto, essa abordagem não funciona para o login da Apple ou SAML. Use essa mitigação apenas se a configuração de proxy reverso na opção 3 for inviável.

A hospedagem do código auxiliar divide-se nas etapas abaixo:

  1. Faça o download dos arquivos para hospedar do local <project>.firebaseapp.com executando os seguintes comandos:

    mkdir signin_helpers/ && cd signin_helpers
    wget https://<project>.firebaseapp.com/__/auth/handler
    wget https://<project>.firebaseapp.com/__/auth/handler.js
    wget https://<project>.firebaseapp.com/__/auth/experiments.js
    wget https://<project>.firebaseapp.com/__/auth/iframe
    wget https://<project>.firebaseapp.com/__/auth/iframe.js
    
  2. Hospede os arquivos acima no domínio do app. Verifique se o servidor da Web pode responder a https://<app domain>/__/auth/<filename>.

    Confira um exemplo de implementação do servidor que faz o download e hospeda os arquivos. Recomendamos que você faça o download e a sincronização dos arquivos periodicamente para garantir que as correções de bugs e os recursos mais recentes sejam usados.

  3. Siga as etapas da Opção 1 para atualizar o redirect_uri autorizado e authDomain. Depois de implantar novamente o app, não haverá mais o acesso ao armazenamento de origem cruzada.

Opção 5: gerenciar o login do provedor de maneira independente

O SDK do Firebase Authentication oferece signInWithPopup() e signInWithRedirect() como métodos práticos para encapsular a lógica complexa e evitar a necessidade de envolver outro SDK. Você pode evitar a necessidade do uso desses métodos fazendo login de maneira independente no seu provedor e, em seguida, usando signInWithCredential() para trocar as credenciais do provedor por uma credencial do Firebase Authentication. Você pode usar, por exemplo, o SDK do Login do Google, o exemplo de código para receber uma credencial da Conta do Google e, em seguida, instanciar uma nova credencial do Google executando o seguinte código:

API modular da Web

  // `googleUser` from the onsuccess Google Sign In callback.
  //  googUser = gapi.auth2.getAuthInstance().currentUser.get();
  const credential = GoogleAuthProvider.credential(googleUser.getAuthResponse().id_token);
  const result = await signInWithCredential(auth, credential);

API com namespace da Web

  // `googleUser` from the onsuccess Google Sign In callback.
  const credential = firebase.auth.GoogleAuthProvider.credential(
      googleUser.getAuthResponse().id_token);
  const result = await firebase.auth().signInWithCredential(credential);

Depois de chamar signInWithCredential(), o restante do app vai funcionar da mesma forma que antes.

Neste link, você encontra instruções sobre como receber uma credencial da Apple.