Logout
Última atualização: 14 de julho de 2026
Visão Geral
Sair da conta precisa deixar o app num estado limpo, sem tokens nem contexto de organização residual, mesmo se a chamada de encerramento de sessão ao Keycloak falhar. O app trata a limpeza local como a parte que não pode falhar, enquanto avisa o Keycloak sobre o logout de forma best-effort.
Arquivos-chave
| Arquivo | Responsabilidade |
|---|---|
services/auth/auth.service.ts | signOut, que chama o Keycloak e sempre limpa o storage local depois |
services/auth/auth.storage.ts | clearAll, que remove tokens, contexto de organização e qualquer PKCE pendente |
providers/auth/auth.provider.tsx | Limpeza adicional em nível de provider, como parar a validação periódica de sessão e limpar a última rota visitada |
O logout no serviço
AuthService.signOut() tenta avisar o Keycloak que a sessão deve ser encerrada, usando o refresh token guardado, mas essa chamada está dentro de um bloco que nunca impede a limpeza local de acontecer:
// auth.service.ts
async signOut(options?: SignOutOptions): Promise<void> {
const tokens = AuthStorage.readTokens();
try {
if (tokens?.refreshToken) {
await logoutWithRefreshToken(tokens.refreshToken);
}
} catch (error) {
console.error("[Auth] Logout failed:", error);
} finally {
AuthStorage.clearAll();
}
},
Isso significa que mesmo sem internet, ou com o Keycloak fora do ar, o usuário sempre consegue sair da conta no dispositivo. A chamada ao Keycloak é uma cortesia para invalidar a sessão do lado do servidor, não uma condição para o logout funcionar localmente.
O que é limpo no storage
AuthStorage.clearAll() remove as três coisas que a autenticação guarda: os tokens principais, o contexto de organização e qualquer PKCE que tenha ficado pendente de um login interrompido.
// auth.storage.ts
clearAll(): void {
this.clearTokens();
this.clearAuthContextsTokens();
this.clearPendingPkce();
},
Cada uma dessas três limpezas notifica os assinantes correspondentes, então isAuthenticated e hasOrganization caem para falso automaticamente em qualquer tela que esteja observando esses hooks, sem que o logout precise saber quais telas existem ou como navegar entre elas.
Limpeza adicional no provider
O AuthProvider cuida de duas coisas que não fazem sentido dentro do serviço de autenticação em si, porque pertencem à camada de navegação e de verificação periódica de sessão:
// auth.provider.tsx
const signOut = useCallback(async () => {
stopSessionValidation();
setHasPendingPostLoginSync(false);
clearLastVisitedRoute();
await AuthService.signOut();
}, [stopSessionValidation]);
Parar a validação periódica evita que o app continue tentando confirmar, a cada quatro minutos, a validade de uma sessão que o próprio usuário acabou de encerrar. Limpar a última rota visitada evita que o próximo login, seja do mesmo usuário ou de outro vendedor no mesmo aparelho, caia de volta numa tela que fazia sentido para a sessão anterior mas não para a nova.
Logout automático por sessão expirada
Existe um segundo caminho que chega ao mesmo AuthService.signOut(), mas não é iniciado por uma ação do usuário. A validação periódica de sessão, descrita em Guardas de Rota e Inicialização, chama esse mesmo método quando confirma que a sessão no Keycloak não está mais ativa:
// auth.provider.tsx
const validateActiveSession = useCallback(async () => {
if (sessionValidationInFlightRef.current) return;
sessionValidationInFlightRef.current = true;
try {
const hasActiveSession = await AuthService.hasActiveKeycloakSession();
if (hasActiveSession === false) {
await AuthService.signOut({ openBrowser: false });
stopSessionValidation();
}
} finally {
sessionValidationInFlightRef.current = false;
}
}, [stopSessionValidation]);
Esse caminho automático chama AuthService.signOut() diretamente, sem passar pela função signOut exposta pelo contexto do provider. Por isso ele também precisa chamar stopSessionValidation() explicitamente, já que o efeito que normalmente para a validação ao detectar isAuthenticated como falso ainda vai disparar, mas de forma assíncrona, e esse caminho não pode depender só dele.
Armadilhas conhecidas
Nunca implemente uma limpeza parcial de storage numa nova funcionalidade de auth. Se um novo dado precisar ser guardado ao lado dos tokens ou do contexto de organização, ele deve ser incluído em clearAll(), ou vai sobreviver a um logout e contaminar a próxima sessão. Também não chame AuthStorage.clearAll() diretamente de uma tela ou de outro serviço fora deste fluxo, sempre passe por AuthService.signOut() ou pelo signOut() do provider, dependendo de onde a chamada está acontecendo, para que a tentativa de encerrar a sessão no Keycloak não seja pulada.