Post publicado
Por que usei cookie httpOnly
10/04/2026
Enquanto construía o Backblog, tomei uma decisão que, a princípio, parecia pequena, mas que impactou significativamente a base do projeto: a autenticação.
O caminho mais rápido seria implementar um login simples, receber um token, armazená-lo no navegador e seguir em frente. Funciona.
No entanto, à medida que o Backblog evoluía para um verdadeiro CMS, com área administrativa, edição de posts e painel protegido, essa abordagem começou a me incomodar. Eu não queria que o frontend fosse o responsável pela gestão da sessão. Preferia que essa parte fosse controlada diretamente pelo servidor.
Por isso, optei por trabalhar com cookie httpOnly. Essa escolha não resolve todos os problemas, mas, para o que eu pretendia no projeto, fazia mais sentido manter a sessão menos exposta no navegador e a estrutura mais organizada.
No final, a lógica ficou simples:
O usuário envia o login.
O backend valida.
O servidor cria a sessão.
Essa sessão é armazenada em um cookie
httpOnly.O middleware protege a área administrativa.
No logout, a sessão é encerrada de fato.
No Backblog, busquei exatamente isso: uma base simples, mas sem comprometer a segurança logo no início.
Login criando a sessão no servidor
// app/api/admin/auth/login/route.ts
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
export async function POST(req: Request) {
const { email, password } = await req.json();
const usuarioValido =
email === "admin@exemplo.com" &&
password === "senha-segura-aqui";
if (!usuarioValido) {
return NextResponse.json(
{ error: "Credenciais inválidas" },
{ status: 401 }
);
}
const sessionToken = "sessao-gerada-no-servidor";
const cookieStore = await cookies();
cookieStore.set("backblog_session", sessionToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
maxAge: 60 * 60 * 24 * 7,
});
return NextResponse.json({ ok: true });
}Protegendo a área administrativa
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(req: NextRequest) {
const session = req.cookies.get("backblog_session")?.value;
if (req.nextUrl.pathname.startsWith("/admin") && !session) {
return NextResponse.redirect(new URL("/login", req.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/admin/:path*"],
};Encerrando a sessão no logout
// app/api/admin/auth/logout/route.ts
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
export async function POST() {
const cookieStore = await cookies();
cookieStore.set("backblog_session", "", {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
path: "/",
maxAge: 0,
});
return NextResponse.json({ ok: true });
}O que mais gostei nessa escolha foi o fato de que cada parte ficou bem definida: o frontend cuida da interface, enquanto o backend gerencia a sessão. Assim, o projeto se mantém simples, sem parecer improvisado.
No final, não foi uma escolha por moda; foi uma decisão que fez mais sentido para o que eu queria construir.