Como gerenciar sessões do IAP

Nesta página, descrevemos como o Identity-Aware Proxy (IAP) processa uma solicitação com uma sessão expirada e como garantir que as solicitações de app AJAX e do WebSocket sejam bem-sucedidas.

Fluxo de sessão do IAP

Ao usar o fluxo de login padrão do IAP, o usuário recebe um cookie de sessão que faz referência à sessão de login do Google. O IAP usa esse cookie para confirmar se o usuário ainda está conectado. O IAP requer que um usuário faça login antes de acessar um app protegido pelo IAP.

As sessões do IAP são atualizadas periodicamente. No entanto, se o usuário estiver usando uma Conta do Google para fazer login, as sessões do IAP também serão vinculadas à sessão de login do Google do usuário. Nesse caso, o IAP só exigirá que o usuário faça login novamente em uma das seguintes situações:

  • O usuário saiu da conta.
  • A conta foi suspensa.
  • A conta requer uma redefinição de senha.

Se um usuário estiver desconectado, o IAP detectará a alteração de estado da Conta do Google dentro de alguns minutos e invalidará a sessão.

O IAP verifica novamente a autorização do gerenciamento de identidade e acesso (IAM) para novas solicitações durante as sessões válidas. As atualizações da política de acesso do IAM de um app protegido por IAP podem levar alguns minutos para entrar em vigor.

Expiração da sessão do IAP

Para um fluxo de login usando uma Conta do Google, a sessão do IAP é vinculada à sessão de login do Google subjacente e expira somente quando essa sessão expira, independentemente da declaração exp no JWT enviada no cabeçalho da autorização.

Na autenticação programática, o IAP cumpre a declaração exp no JWT enviado no cabeçalho "Authorization".

No fluxo de login do Identity Platform, a sessão do IAP permanece válida por até uma hora após o usuário sair.

Solicitações WebSocket

O IAP só oferece suporte a WebSocket para solicitações iniciais e não verifica a autorização continuamente. Quando uma solicitação WebSocket é recebida, ela começa com uma solicitação HTTP Upgrade. O IAP avalia isso como uma solicitação GET HTTP padrão. Depois que a solicitação é autorizada, o IAP transmite a solicitação para o servidor, abrindo uma conexão permanente. Depois disso, o IAP não monitora as solicitações nem atualiza a sessão.

Respostas de sessão expiradas

O IAP retorna respostas diferentes para sessões expiradas com base no tipo de solicitação.

Solicitações não AJAX

Em solicitações não AJAX, o usuário é redirecionado para o fluxo de login para atualizar a sessão. Se o usuário ainda estiver conectado, esse redirecionamento será transparente.

Solicitações AJAX

O Chrome e outros navegadores estão descontinuando os cookies de terceiros. As recomendações para fazer solicitações AJAX nesta página não vão funcionar se os cookies de terceiros estiverem desativados. No entanto, as recomendações fornecidas permanecerão funcionais se a origem e o destino das solicitações AJAX forem do mesmo site.

Para instruções sobre como gerenciar cookies de terceiros no Chrome, consulte Excluir, permitir e gerenciar cookies no Chrome.

O IAP depende dos cookies para gerenciar as sessões dos usuários. Ele também depende de uma sequência de redirecionamentos para estabelecer uma sessão como parte de um fluxo de login. Estabelecer uma sessão nem sempre é possível se o aplicativo usar o compartilhamento de recursos entre origens (CORS, na sigla em inglês) para fazer solicitações AJAX para um aplicativo protegido pelo IAP.

Para fazer uma solicitação CORS com sucesso para um aplicativo protegido por IAP, é necessário estabelecer uma sessão de IAP que esteja fora de banda. Observe que, para uma solicitação AJAX que envia uma solicitação CORS de source_domain->target_domain em que target_domain hospeda o aplicativo protegido pelo IAP, é necessário que haja uma sessão estabelecida na target_domain. Não há como compartilhar cookies entre source_domain e target_domain.

Depois que a sessão em target_domain for estabelecida, o desenvolvedor precisará ativar o envio das credenciais na solicitação. Por padrão, os métodos JavaScript não anexam cookies às solicitações. Para ativar credenciais na solicitação, as solicitações enviadas com um objeto XMLHttpRequest precisam da propriedade withCredentials definida como verdadeira, enquanto as solicitações com o Fetch API precisa da opção credentials definida como include ou same-origin.

O guia a seguir recomenda um padrão para desenvolvedores da Web estabelecerem e atualizarem uma sessão do IAP com êxito.

Noções básicas sobre a resposta do IAP

Para solicitações AJAX, o IAP retorna um código de status HTTP 401: Unauthorized. Observe que a detecção de solicitações AJAX não pode ser feita com perfeição. Se você estiver recebendo uma resposta de código de status 302, em vez de 401 para solicitações AJAX, um cabeçalho X-Requested-With com valor "XMLHttpRequest" pode ser a solicitações AJAX. Isso informa ao IAP que a solicitação tem origem no JavaScript.

Como processar uma resposta HTTP 401 da solicitação AJAX

Para estabelecer uma sessão do IAP após o aplicativo receber HTTP 401, ele pode abrir uma nova janela para o URL target_domain + ?gcp-iap-mode=DO_SESSION_REFRESH. Esse é um gerenciador especial que estabelece apenas a sessão do IAP em target_domain. Se a janela for mantida como aberta, ela continuará atualizando a sessão periodicamente, solicitando a entrada do usuário conforme necessário. Opcionalmente, o usuário pode optar por fechar a janela e o gerenciador do status HTTP 401 no código do desenvolvedor deve abrir uma janela novamente para a atualização da sessão conforme necessário.

Etapa 1: modificar o código do app

O exemplo a seguir mostra como modificar o código do app para processar o código de status HTTP 401 e fornecer um link de atualização de sessão para o usuário:

if (response.status === 401) {
  statusElm.innerHTML = 'Login stale. <input type="button" value="Refresh" onclick="sessionRefreshClicked();"/>';
}
Etapa 2: instalar um gerenciador onclick

O código de amostra abaixo instala um gerenciador onclick que fecha a janela após a atualização da sessão:

var iapSessionRefreshWindow = null;

function sessionRefreshClicked() {
  if (iapSessionRefreshWindow == null) {
    iapSessionRefreshWindow = window.open("/?gcp-iap-mode=DO_SESSION_REFRESH");
    window.setTimeout(checkSessionRefresh, 500);
  }
  return false;
}

function checkSessionRefresh() {
  if (iapSessionRefreshWindow != null && !iapSessionRefreshWindow.closed) {
    fetch('/favicon.ico').then(function(response) {
      if (response.status === 401) {
        window.setTimeout(checkSessionRefresh, 500);
      } else {
        iapSessionRefreshWindow.close();
        iapSessionRefreshWindow = null;
      }
    });
  } else {
    iapSessionRefreshWindow = null;
  }
}