Autenticação baseada em sessão e cookie no back-end

Capítulo 3

Tempo estimado de leitura: 9 minutos

+ Exercício

O que é autenticação por sessão e cookie

Na autenticação baseada em sessão, o back-end mantém um estado: após o login, ele cria uma sessão (um registro no servidor) e entrega ao cliente um identificador de sessão (session id) normalmente via cookie. Em cada requisição seguinte, o navegador envia automaticamente esse cookie; o servidor usa o session id para localizar a sessão e, a partir dela, identificar o usuário autenticado.

Componentes típicos:

  • Cookie de sessão: armazena o session id no cliente (não deve armazenar dados sensíveis).
  • Store de sessão: onde o servidor guarda o estado da sessão (ex.: userId, data de expiração, metadados).
  • Middleware de sessão: lê o cookie, carrega a sessão e anexa o usuário ao contexto da requisição.
  • Logout: invalida a sessão no store e remove/expira o cookie.

Modelo de sessão do zero: estrutura e fluxo

Estrutura mínima de uma sessão

Uma sessão pode ser representada por um registro com campos como:

  • id: identificador aleatório (session id).
  • userId: referência ao usuário autenticado.
  • createdAt, lastSeenAt: auditoria e renovação.
  • expiresAt: expiração absoluta.
  • revokedAt (opcional): marca de revogação.
  • ip, userAgent (opcional): detecção de anomalias.

Passo a passo: criação de sessão no login

  1. Validar credenciais (ex.: email/senha).
  2. Gerar um session id criptograficamente seguro.
  3. Persistir a sessão no store associando sessionId ao userId e definindo expiresAt.
  4. Enviar cookie com o session id e atributos de segurança.
  5. Responder com dados não sensíveis (ex.: perfil básico) se necessário.

Passo a passo: autenticação em requisições subsequentes

  1. O navegador envia o cookie automaticamente.
  2. O middleware lê o cookie e extrai o session id.
  3. O servidor busca a sessão no store.
  4. Se existir e estiver válida (não expirada/revogada), anexa req.user (ou equivalente) e permite seguir.
  5. Se inválida, retorna 401 e opcionalmente expira o cookie.

Passo a passo: invalidação no logout

  1. Identificar a sessão atual via cookie.
  2. Remover a sessão do store (ou marcar como revogada).
  3. Enviar um Set-Cookie para expirar o cookie no cliente.

Endpoints típicos e comportamento esperado

POST /login

Cria sessão e define cookie.

POST /login { email, password }

Resposta (exemplo):

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

200 OK { user: { id, name } }

GET /me

Requer sessão válida; retorna dados do usuário autenticado.

GET /me

Resposta (exemplo):

200 OK { id, name, email }

POST /logout

Invalida sessão e expira cookie.

POST /logout

Resposta (exemplo):

204 No Content

Pseudocódigo: criação, leitura e invalidação de sessão

Gerando um session id seguro

O session id deve ser imprevisível. Use um gerador criptográfico e codifique em base64url/hex.

function generateSessionId() {  bytes = cryptoRandomBytes(32)  return base64urlEncode(bytes) }

Store de sessão (interface)

Defina uma interface para trocar o backend de armazenamento sem reescrever o middleware.

interface SessionStore {  get(sessionId): Session|null  set(sessionId, session, ttlSeconds): void  delete(sessionId): void }

Login: criar sessão e setar cookie

function loginHandler(req, res) {  { email, password } = req.body  user = Users.findByEmail(email)  if (!user || !verifyPassword(password, user.passwordHash)) {    return res.status(401).json({ error: "invalid_credentials" })  }  sessionId = generateSessionId()  now = nowUtc()  ttlSeconds = 60 * 60 * 24 * 7 // 7 dias  session = {    id: sessionId,    userId: user.id,    createdAt: now,    lastSeenAt: now,    expiresAt: now + ttlSeconds,    userAgent: req.headers["user-agent"],    ip: req.ip  }  SessionStore.set(sessionId, session, ttlSeconds)  res.setCookie("sid", sessionId, {    httpOnly: true,    secure: true,    sameSite: "Lax",    path: "/",    maxAge: ttlSeconds  })  return res.json({ user: { id: user.id, name: user.name } }) }

Middleware de sessão: carregar sessão e anexar usuário

function sessionMiddleware(req, res, next) {  sid = req.cookies["sid"]  if (!sid) {    req.session = null    req.user = null    return next()  }  session = SessionStore.get(sid)  if (!session) {    // cookie pode estar stale; expira no cliente para reduzir ruído    res.setCookie("sid", "", { path: "/", maxAge: 0 })    req.session = null    req.user = null    return next()  }  if (session.expiresAt < nowUtc()) {    SessionStore.delete(sid)    res.setCookie("sid", "", { path: "/", maxAge: 0 })    req.session = null    req.user = null    return next()  }  // opcional: sliding session (renovar lastSeen/TTL)  session.lastSeenAt = nowUtc()  // se store suportar, renove TTL aqui  // SessionStore.set(sid, session, newTtlSeconds)  req.session = session  req.user = Users.findById(session.userId)  return next() }

Middleware de autenticação: bloquear rotas protegidas

function requireAuth(req, res, next) {  if (!req.user) {    return res.status(401).json({ error: "unauthenticated" })  }  return next() }

Logout: invalidar sessão

function logoutHandler(req, res) {  sid = req.cookies["sid"]  if (sid) {    SessionStore.delete(sid)  }  res.setCookie("sid", "", { path: "/", maxAge: 0, httpOnly: true, secure: true, sameSite: "Lax" })  return res.status(204).send() }

Armazenamento de sessão: memória vs banco vs cache (Redis)

1) Sessão em memória (in-process)

Como funciona: um mapa/dicionário no próprio processo do servidor (ex.: Map<sid, session>).

  • Vantagens: simples, rápido, sem dependências externas.
  • Desvantagens: não escala horizontalmente; ao subir múltiplas instâncias, cada uma tem seu próprio mapa. Se o balanceador enviar o usuário para outra instância, a sessão “some”. Reinícios derrubam todas as sessões.
  • Implicações: para funcionar com múltiplas instâncias, exigiria sticky sessions no balanceador, o que reduz flexibilidade e pode complicar alta disponibilidade.

2) Sessão em banco de dados (relacional ou NoSQL)

Como funciona: tabela/coleção de sessões com índice por id e campos de expiração.

  • Vantagens: persistência; funciona bem com múltiplas instâncias; facilita auditoria e revogação; backups e replicação podem ajudar em HA.
  • Desvantagens: latência maior que memória/cache; alto volume de leitura por requisição pode pressionar o banco; exige limpeza de sessões expiradas (job/TTL).
  • Implicações: em sistemas com muito tráfego, o banco pode virar gargalo; é comum usar cache para sessões ou migrar para store dedicado.

3) Sessão em cache distribuído (ex.: Redis)

Como funciona: chave-valor com TTL nativo (ex.: SET sid value EX ttl).

  • Vantagens: baixa latência; TTL nativo simplifica expiração; adequado para múltiplas instâncias; bom para alto volume.
  • Desvantagens: requer infraestrutura extra; precisa planejar persistência (RDB/AOF) conforme tolerância a perda; falhas podem derrubar autenticação se não houver HA.
  • Implicações de escalabilidade: facilita escalar horizontalmente o app; o store centralizado mantém consistência de sessão entre instâncias.
  • Implicações de alta disponibilidade: use Redis com replicação e failover (ex.: Sentinel/Cluster) e configure timeouts/retries para não travar requisições.

Tabela comparativa

StoreEscala horizontalLatênciaPersistênciaComplexidadeHA
MemóriaRuim (depende de sticky)Muito baixaNãoBaixaBaixa
BancoBoaMédiaSimMédiaMédia/Alta (com réplica)
RedisExcelenteBaixaOpcionalMédia/AltaAlta (com cluster/failover)

Configuração segura de cookies de sessão

O cookie é o “portador” do session id. Se ele for roubado, um atacante pode sequestrar a sessão. Por isso, os atributos do cookie são parte central da segurança.

HttpOnly

  • O que faz: impede acesso ao cookie via JavaScript (document.cookie).
  • Por que importa: reduz impacto de XSS no roubo de sessão.
  • Recomendação: habilitar sempre para cookie de sessão.

Secure

  • O que faz: cookie só é enviado via HTTPS.
  • Por que importa: evita vazamento em HTTP.
  • Recomendação: habilitar em produção; em dev local pode exigir HTTPS local ou exceção controlada.

SameSite (Lax/Strict/None)

  • O que faz: controla envio do cookie em navegação cross-site, mitigando CSRF.
  • Lax: bom padrão para apps tradicionais; envia cookie em navegação de topo (ex.: clicar em link), mas bloqueia muitos POSTs cross-site.
  • Strict: mais restritivo; pode quebrar fluxos legítimos (ex.: entrar via link externo e já estar logado).
  • None: necessário para cenários cross-site (ex.: front-end em um domínio e API em outro) e exige Secure.

Path

  • O que faz: restringe para quais caminhos o cookie é enviado.
  • Recomendação: use / se a sessão vale para toda a aplicação; use um path mais específico se quiser limitar escopo (ex.: /api).

Domain

  • O que faz: define quais hosts recebem o cookie.
  • Recomendação: evite definir Domain quando não necessário (deixe host-only), reduzindo superfície. Se precisar compartilhar entre subdomínios (ex.: app.exemplo.com e api.exemplo.com), configure cuidadosamente (ex.: Domain=exemplo.com).

Tempo de vida: Expires/Max-Age e sessão deslizante

  • Cookie de sessão (sem Expires/Max-Age): tende a expirar ao fechar o navegador, mas não é garantia de segurança por si só.
  • Cookie persistente (com Max-Age/Expires): permanece até expirar; melhora UX, aumenta janela de risco se roubado.
  • TTL no store: deve existir mesmo se o cookie for persistente; o servidor precisa expirar sessões no lado dele.
  • Sessão deslizante (sliding): renova TTL a cada uso; melhora conveniência, mas pode manter sessões vivas indefinidamente. Uma alternativa é combinar expiração absoluta (ex.: 7 dias) com expiração por inatividade (ex.: 30 min).

Exemplo de Set-Cookie recomendado

Set-Cookie: sid=BASE64URL_RANDOM; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=604800

Cuidados práticos e armadilhas comuns

Não coloque dados sensíveis no cookie

O cookie deve conter apenas um identificador opaco (session id). Dados do usuário ficam no store.

Rotação de session id (mitigar fixation)

Após login bem-sucedido, gere um novo session id (não reaproveite um id pré-existente). Se houver sessão anônima antes do login, invalide-a e crie outra autenticada.

Revogação e múltiplas sessões

Decida se um usuário pode ter múltiplas sessões (vários dispositivos). Se quiser limitar, ao criar uma nova sessão você pode revogar as anteriores do mesmo usuário (ex.: manter apenas a mais recente) ou oferecer endpoint para listar e revogar sessões.

Limpeza de sessões expiradas

  • Memória: varredura periódica para remover expiradas.
  • Banco: job periódico (DELETE WHERE expiresAt < now) e índice em expiresAt.
  • Redis: TTL nativo já remove automaticamente, mas ainda é útil ter métricas e alertas.

Quando o front-end e a API estão em domínios diferentes

Se o cookie precisar ser enviado em contexto cross-site, normalmente será necessário SameSite=None; Secure e configuração correta de CORS com credenciais (ex.: permitir credentials e origin explícita). Além disso, o atributo Domain pode ser necessário para compartilhar entre subdomínios, mas deve ser usado com cautela.

Agora responda o exercício sobre o conteúdo:

Em um sistema de autenticação baseado em sessão e cookie, qual fluxo descreve corretamente como o back-end identifica o usuário em requisições subsequentes ao login?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Na autenticação por sessão, o cookie carrega apenas um identificador opaco (session id). A cada requisição, o servidor usa esse id para localizar a sessão no store e, se estiver válida (não expirada/revogada), identifica o usuário no contexto.

Próximo capitúlo

Gerenciamento de sessão: expiração, rotação e revogação

Arrow Right Icon
Capa do Ebook gratuito Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas
17%

Autenticação e Autorização no Back-end: Sessões, JWT e Boas Práticas

Novo curso

18 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.