Conn2Flow
Navegação das docs

SDD

Requisição 175 — Renovação Silenciosa de Token CSRF (Silent Refresh & Retry) e Recuperação Graciosa de Sessão no Core e `global.js`

Origem: Relato de degradação de UX/segurança ao manter abas abertas em inatividade (ex: módulo Busca Clínica, painéis administrativos ou páginas públicas). O token CSRF/sessão…

Origem: Relato de degradação de UX/segurança ao manter abas abertas em inatividade (ex: módulo Busca Clínica, painéis administrativos ou páginas públicas). O token CSRF/sessão expira e requisições subsequentes de mutação (POST/PUT/DELETE/AJAX/Fetch/XHR) falham com HTTP 403 ("Token CSRF inválido ou ausente"), exibindo erros crus ou travando a interface. Lote Vinculado: BATCH-180. Status: ready-for-intake.


1. Diagnóstico e Causa-Raiz

1.1 Cenário Atual

  1. Expiração Silenciosa: O usuário autenticado ou visitante abre uma tela do sistema (como Busca Clínica, painel do Gestor ou formulários) e deixa a aba em segundo plano ou ociosa por determinado período.

  2. Falha de Requisição Mutável: Ao retornar e interagir com a tela (disparando requisições AJAX, fetch ou XMLHttpRequest mutáveis como POST, PUT ou DELETE), o backend valida o token CSRF em seguranca_csrf_requisicao_validar().

  3. Resposta 403 Rígida: O backend identifica a discrepância ou ausência do token e executa gestor_csrf_resposta_invalida() (em gestor/gestor.php), devolvendo HTTP 403 com JSON {"status":"error","message":"Token CSRF inválido ou ausente."}.

  4. Degradação de Experiência do Usuário (UX):

    • A camada de frontend atual (gestor/assets/global/global.js) anexa o token atual no envio (X-CSRF-Token e _csrf_token), mas não possui lógica de interceptação de 403 CSRF, renovação sob demanda (Silent Refresh) nem fila de repetição transparente (Retry).

    • O usuário recebe mensagens técnicas confusas ("Erro 403", "Acesso Negado") ou tem seu fluxo interrompido com perda dos dados preenchidos no formulário/busca, mesmo quando a sessão do usuário ainda está viva no servidor ou pode ser recuperada.


2. Escopo Normativo da Solução

2.1 Backend: Endpoint de Token CSRF e Identificador de Erro Padronizado

  1. Endpoint de Consulta/Renovação de CSRF:

    • Expor uma rota leve de sistema no roteador central (gestor/gestor.php), por exemplo _gestor-csrf-token (ou _gestor-csrf-refresh).

    • A rota deve responder JSON estruturado com o token CSRF ativo da sessão (gestor_csrf_token()) e o status da sessão:

      {
      "status": "success",
      "token": "...",
      "authenticated": true
      }
    • Em caso de sessão destruída/inválida para áreas que exigem autenticação obrigatória, responder com código de erro correspondente (AUTH_EXPIRED ou SESSION_EXPIRED) e cabeçalho X-Gestor-Auth-Redirect para login gracioso.

    • A rota _gestor-csrf-token deve ser isenta de validação prévia de CSRF em seguranca_csrf_requisicao_validar() para leitura.

  2. Identificador de Máquina no Erro 403 (gestor_csrf_resposta_invalida):

    • Atualizar a resposta JSON de gestor_csrf_resposta_invalida() em gestor/gestor.php para incluir um código de erro padronizado:

      {
      "status": "error",
      "code": "CSRF_INVALID_OR_EXPIRED",
      "message": "Token CSRF inválido ou ausente."
      }
    • Isso permite que interceptores de frontend diferenciem de forma determinística um erro de CSRF expirado de outros erros de permissão ou bloqueio (como 403 de perfil/ACL).

2.2 Frontend (global.js): Silent Refresh & Retry Queue

  1. Fila de Requisições e Mecanismo de Renovação Concorrente:

    • Em gestor/assets/global/global.js, implementar um gerenciador de renovação de token (renovarCsrf()):

      • Ao detectar uma falha HTTP 403 com code === 'CSRF_INVALID_OR_EXPIRED' (ou mensagem de CSRF) em chamadas de $.ajax, window.fetch ou XMLHttpRequest:

      • Se uma renovação já estiver em andamento, enfileirar a requisição para retry automático.

      • Se não estiver em andamento, disparar a requisição de renovação para _gestor-csrf-token.

      • Ao receber o novo token:

      • Atualizar window.gestor.csrfToken e a tag <meta name="csrf-token" content="...">.

      • Se executando em iframe (srcdoc ou child frame), propagar para window.parent.gestor.csrfToken quando aplicável.

      • Re-executar (retry) todas as requisições enfileiradas atualizando seus cabeçalhos X-CSRF-Token e parâmetros _csrf_token.

      • Se a renovação falhar (sessão encerrada/401/403 irrecuperável):

      • Rejeitar as requisições enfileiradas e disparar a recuperação graciosa de sessão.

  2. Detecção Proativa de Foco / Retorno à Aba (visibilitychange):

    • Registrar um listener de visibilitychange no document com controle de frequência (throttling/debounce de ~30 segundos):

      • Quando document.visibilityState === 'visible', se a aba esteve em segundo plano por tempo significativo, efetuar uma verificação/atualização silenciosa do token CSRF em background.

      • Assim, quando o usuário clicar em qualquer ação após horas de inatividade, o token já estará atualizado antes mesmo do primeiro clique.

  3. Recuperação Graciosa em Caso de Sessão Encerrada:

    • Se a renovação constatar que a sessão de login expirou definitivamente:

      • Exibir modal amigável de sessão expirada ou efetuar redirecionamento transparente para /signin/ preservando a URL de retorno (redirecionar-local / query string), evitando travamento em branco ou alert técnico.


3. Critérios de Aceite e Validação

  1. Endpoint _gestor-csrf-token Funcional:

    • Requisições GET/AJAX para _gestor-csrf-token retornam HTTP 200 com JSON { status: 'success', token: '...' }.

  2. Replay Transparente de Requisições AJAX/Fetch/XHR:

    • Requisições POST que receberem 403 por token expirado realizam a renovação automática e completam a operação com sucesso sem que o usuário perceba o erro.

  3. Tratamento de Múltiplas Requisições Simultâneas:

    • Múltiplas requisições concorrentes falhando por CSRF disparam apenas UMA chamada de renovação e todas são retentadas após a obtenção do novo token.

  4. Isolamento de Erros de Permissão Genuínos:

    • Erros 403 por falta de permissão de acesso (ACL) ou acesso restrito continuam sendo tratados como negações legítimas e não entram em loop de retry.

  5. Testes Automatizados:

    • Testes unitários no PHPUnit (tests/Unit/PHP/) cobrindo o endpoint de CSRF e código padronizado de erro.

    • Testes no Vitest (tests/Unit/JS/) cobrindo a fila de retry, silent refresh, atualização de meta tag e visibilitychange.

    • Suítes de testes 100% verdes com exit 0.

O Futuro é Híbrido: Humano + IA.

O Conn2Flow é a ferramenta. Se você precisa do Arquiteto para desenhar a estratégia da sua empresa usando essa tecnologia...

Contrate Consultoria Especializada