Autenticação

Logout

Como realizar logout seguro da API

O logout é o processo de invalidar tokens de acesso e garantir que a sessão seja encerrada de forma segura na API da Nuvende.

Como Funciona o Logout

O logout na API da Nuvende é um processo simples que invalida o token de acesso atual. Quando você faz logout:

  1. Token é Invalidado: O access token usado na requisição é marcado como inválido
  2. Sessão Encerrada: O token não pode mais ser usado para acessar endpoints protegidos
  3. Segurança Garantida: Qualquer tentativa de usar o token invalidado retornará erro 401

Por que Fazer Logout?

  • Segurança: Impede que tokens sejam usados indevidamente
  • Controle de Sessão: Permite encerrar sessões ativas explicitamente
  • Boas Práticas: Recomendado para aplicações que gerenciam múltiplos usuários
  • Conformidade: Necessário para aplicações que seguem padrões de segurança

Implementação

Endpoint Oficial

URL: POST /api/v2/auth/logout
Ambiente Homologação: https://api-h.nuvende.com.br/api/v2/auth/logout
Ambiente Produção: https://api.nuvende.com.br/api/v2/auth/logout

Headers Obrigatórios

  • Authorization: Bearer {access_token} - Token de acesso a ser invalidado

Exemplo de Requisição

curl -X POST https://api-h.nuvende.com.br/api/v2/auth/logout \
  -H "Authorization: Bearer seu_access_token"

Resposta de Sucesso

{
  "message": "Successfully logged out"
}

Explicação da Resposta:

  • message: Confirmação de que o logout foi realizado com sucesso
  • Após esta resposta, o token usado na requisição não pode mais ser utilizado

Implementação em Código

JavaScript/Node.js - Implementação Completa

Vamos integrar o logout à classe NuvendeAuth que criamos na página de login:

const axios = require('axios');

class NuvendeAuth {
  constructor(clientId, clientSecret, baseUrl) {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.baseUrl = baseUrl;
    this.accessToken = null;
    this.tokenExpiry = null;
  }

  // ... outros métodos da classe (getAccessToken, etc.) ...

  /**
   * Realiza logout invalidando o token de acesso atual
   * Após o logout, o token não pode mais ser usado
   */
  async logout() {
    // Verificar se temos um token para invalidar
    if (!this.accessToken) {
      console.log('Nenhum token ativo para fazer logout');
      return { message: 'Nenhum token ativo' };
    }

    try {
      console.log('Realizando logout...');
      
      const response = await axios.post(`${this.baseUrl}/api/v2/auth/logout`, {}, {
        headers: {
          'Authorization': `Bearer ${this.accessToken}`
        }
      });

      // Limpar tokens locais após logout bem-sucedido
      this.clearTokens();
      
      console.log('Logout realizado com sucesso');
      return response.data;
      
    } catch (error) {
      console.error('Erro no logout:', error.response?.data || error.message);
      
      // Mesmo com erro, limpar tokens locais por segurança
      this.clearTokens();
      
      throw error;
    }
  }

  /**
   * Limpa todos os tokens armazenados localmente
   * Deve ser chamado após logout ou em caso de erro de autenticação
   */
  clearTokens() {
    this.accessToken = null;
    this.tokenExpiry = null;
    console.log('Tokens locais limpos');
  }

  /**
   * Verifica se há um token ativo
   */
  isAuthenticated() {
    return this.accessToken !== null;
  }
}

// Exemplo de uso prático
async function exemploLogout() {
  const nuvende = new NuvendeAuth(
    process.env.NUVENDE_CLIENT_ID,
    process.env.NUVENDE_CLIENT_SECRET,
    'https://api-h.nuvende.com.br'
  );

  try {
    // Fazer login primeiro
    await nuvende.getAccessToken();
    console.log('Usuário autenticado');

    // Fazer algumas operações...
    console.log('Realizando operações...');

    // Fazer logout
    await nuvende.logout();
    console.log('Logout realizado com sucesso');

    // Verificar se ainda está autenticado
    console.log('Ainda autenticado?', nuvende.isAuthenticated()); // false

  } catch (error) {
    console.error('Erro:', error.message);
  }
}

Python - Implementação Completa

import requests
import time
from datetime import datetime

class NuvendeAuth:
    def __init__(self, client_id, client_secret, base_url):
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = base_url
        self.access_token = None
        self.token_expiry = None

    # ... outros métodos da classe (get_access_token, etc.) ...

    def logout(self):
        """
        Realiza logout invalidando o token de acesso atual
        Após o logout, o token não pode mais ser usado
        """
        if not self.access_token:
            print("Nenhum token ativo para fazer logout")
            return {"message": "Nenhum token ativo"}

        try:
            print("Realizando logout...")
            
            headers = {
                'Authorization': f'Bearer {self.access_token}'
            }
            
            response = requests.post(
                f"{self.base_url}/api/v2/auth/logout",
                headers=headers
            )
            
            response.raise_for_status()
            
            # Limpar tokens locais após logout bem-sucedido
            self.clear_tokens()
            
            print("Logout realizado com sucesso")
            return response.json()
            
        except requests.exceptions.RequestException as e:
            print(f"Erro no logout: {e}")
            
            # Mesmo com erro, limpar tokens locais por segurança
            self.clear_tokens()
            
            raise

    def clear_tokens(self):
        """
        Limpa todos os tokens armazenados localmente
        Deve ser chamado após logout ou em caso de erro de autenticação
        """
        self.access_token = None
        self.token_expiry = None
        print("Tokens locais limpos")

    def is_authenticated(self):
        """
        Verifica se há um token ativo
        """
        return self.access_token is not None

# Exemplo de uso prático
async def exemplo_logout():
    nuvende = NuvendeAuth(
        os.getenv('NUVENDE_CLIENT_ID'),
        os.getenv('NUVENDE_CLIENT_SECRET'),
        'https://api-h.nuvende.com.br'
    )

    try:
        # Fazer login primeiro
        await nuvende.get_access_token()
        print("Usuário autenticado")

        # Fazer algumas operações...
        print("Realizando operações...")

        # Fazer logout
        await nuvende.logout()
        print("Logout realizado com sucesso")

        # Verificar se ainda está autenticado
        print(f"Ainda autenticado? {nuvende.is_authenticated()}")  # False

    except Exception as error:
        print(f"Erro: {error}")

Boas Práticas de Segurança

Limpeza Completa de Tokens

Após fazer logout, é importante limpar todos os vestígios de tokens no cliente:

// Limpar tokens do localStorage/sessionStorage
function clearStoredTokens() {
  localStorage.removeItem('nuvende_access_token');
  localStorage.removeItem('nuvende_refresh_token');
  localStorage.removeItem('nuvende_token_expiry');
  sessionStorage.removeItem('nuvende_access_token');
  sessionStorage.removeItem('nuvende_refresh_token');
  sessionStorage.removeItem('nuvende_token_expiry');
}

// Limpar cookies de autenticação
function clearAuthCookies() {
  document.cookie = 'nuvende_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
  document.cookie = 'nuvende_refresh_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
}

// Limpar dados da memória
function clearMemoryTokens() {
  // Se estiver usando variáveis globais
  window.nuvendeToken = null;
  window.nuvendeRefreshToken = null;
}

Middleware de Segurança

Para aplicações web, implemente middleware que verifica tokens invalidados:

// Express.js middleware para verificar tokens
function authMiddleware(req, res, next) {
  const token = req.headers.authorization?.replace('Bearer ', '');
  
  if (!token) {
    return res.status(401).json({ error: 'Token não fornecido' });
  }
  
  // Aqui você pode verificar se o token foi invalidado
  // (implementar cache ou banco de tokens invalidados)
  if (isTokenInvalidated(token)) {
    return res.status(401).json({ 
      error: 'Token invalidado. Faça login novamente.' 
    });
  }
  
  next();
}

// Função para verificar se token foi invalidado
function isTokenInvalidated(token) {
  // Implementar lógica para verificar se token está na lista de invalidados
  // Pode usar Redis, banco de dados ou cache em memória
  return false; // Implementar conforme sua arquitetura
}

Tratamento de Erros

Códigos de Resposta HTTP

CódigoSignificadoQuando OcorreComo Resolver
200OKLogout realizado com sucesso-
401UnauthorizedToken inválido ou expiradoFazer login novamente
500Internal Server ErrorErro interno do servidorTentar novamente mais tarde

Implementação Robusta de Tratamento de Erros

class LogoutErrorHandler {
  static handleLogoutError(error) {
    const status = error.response?.status;
    const data = error.response?.data;
    
    switch (status) {
      case 401:
        console.error('❌ Token inválido ou expirado:', data);
        // Redirecionar para login ou solicitar nova autenticação
        this.redirectToLogin();
        break;
        
      case 500:
        console.error('❌ Erro interno do servidor:', data);
        // Tentar novamente após um tempo
        setTimeout(() => this.retryLogout(), 5000);
        break;
        
      default:
        console.error('❌ Erro inesperado no logout:', error.message);
        // Limpar tokens locais mesmo com erro
        this.clearLocalTokens();
    }
  }
  
  static redirectToLogin() {
    // Implementar redirecionamento para página de login
    window.location.href = '/login';
  }
  
  static retryLogout() {
    // Implementar retry do logout
    console.log('Tentando logout novamente...');
  }
  
  static clearLocalTokens() {
    // Limpar tokens locais em caso de erro
    localStorage.removeItem('nuvende_access_token');
    localStorage.removeItem('nuvende_refresh_token');
  }
}

Cenários de Uso Comuns

1. Logout Manual do Usuário

// Quando usuário clica em "Sair"
async function handleUserLogout() {
  try {
    await nuvende.logout();
    clearStoredTokens();
    clearAuthCookies();
    redirectToLogin();
  } catch (error) {
    LogoutErrorHandler.handleLogoutError(error);
  }
}

2. Logout Automático por Inatividade

// Logout automático após período de inatividade
let inactivityTimer;

function resetInactivityTimer() {
  clearTimeout(inactivityTimer);
  inactivityTimer = setTimeout(async () => {
    console.log('Inatividade detectada, fazendo logout...');
    await nuvende.logout();
    clearStoredTokens();
    redirectToLogin();
  }, 30 * 60 * 1000); // 30 minutos
}

// Resetar timer em eventos de atividade
document.addEventListener('mousemove', resetInactivityTimer);
document.addEventListener('keypress', resetInactivityTimer);

3. Logout por Segurança

// Logout imediato em caso de suspeita de segurança
async function securityLogout() {
  try {
    // Fazer logout no servidor
    await nuvende.logout();
  } catch (error) {
    // Mesmo com erro, limpar dados locais
    console.error('Erro no logout de segurança:', error);
  } finally {
    // Sempre limpar dados locais
    clearStoredTokens();
    clearAuthCookies();
    clearMemoryTokens();
    redirectToLogin();
  }
}

2025 © Nuvende - CNPJ 38.297.374/0001-93