fix: add /api/auth/signout route and sign-out link to scheduler

- New GET/POST handler at /api/auth/signout deletes the DB session and
  clears all NextAuth cookies (respecting NEXTAUTH_COOKIE_DOMAIN so the
  shared .internal.vyntehome.com cookies are properly evicted)
- Added NEXTAUTH_COOKIE_DOMAIN to scheduler service env in docker-compose
- Sign-out link in AppShell profile block so logout is accessible from the UI
This commit is contained in:
Zachariah K. Sharma
2026-06-14 17:55:56 -06:00
parent 5d59b36ad8
commit aacf7dbbba
4 changed files with 61 additions and 0 deletions
@@ -0,0 +1,48 @@
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import prisma from "@calcom/prisma";
const AUTH_COOKIE_NAMES = [
"next-auth.session-token",
"__Secure-next-auth.session-token",
"next-auth.callback-url",
"next-auth.csrf-token",
"__Host-next-auth.csrf-token",
];
function baseUrl(): string {
const nextAuthUrl = process.env.NEXTAUTH_URL ?? "";
try {
return new URL(nextAuthUrl).origin;
} catch {
return "/";
}
}
async function handleSignOut(): Promise<NextResponse> {
const cookieStore = await cookies();
const sessionToken =
cookieStore.get("__Secure-next-auth.session-token")?.value ??
cookieStore.get("next-auth.session-token")?.value;
if (sessionToken) {
await prisma.session.deleteMany({ where: { sessionToken } }).catch(() => null);
}
const res = NextResponse.redirect(new URL("/", baseUrl()), { status: 302 });
const cookieDomain = process.env.NEXTAUTH_COOKIE_DOMAIN || undefined;
for (const name of AUTH_COOKIE_NAMES) {
res.cookies.set(name, "", {
maxAge: 0,
path: "/",
...(cookieDomain ? { domain: cookieDomain } : {}),
});
}
return res;
}
export const GET = handleSignOut;
export const POST = handleSignOut;
+11
View File
@@ -183,6 +183,17 @@ input[type="number"]::-webkit-inner-spin-button { filter: invert(0.5); }
letter-spacing: 0.04em;
}
.signout-link {
display: block;
margin-top: 10px;
font-size: 10.5px;
color: var(--text-3);
text-decoration: none;
letter-spacing: 0.04em;
transition: color 0.15s;
}
.signout-link:hover { color: var(--text-2); }
.main-surface {
padding: 28px 26px;
min-width: 0;
+1
View File
@@ -42,6 +42,7 @@ export function AppShell({
<div className="profile-block">
<strong>{user.name}</strong>
<span>{user.timeZone}</span>
<a href="/api/auth/signout" className="signout-link">Sign out</a>
</div>
</aside>
<main className="main-surface">{children}</main>
+1
View File
@@ -150,6 +150,7 @@ services:
NODE_ENV: production
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
NEXTAUTH_URL: ${NEXTAUTH_URL}
NEXTAUTH_COOKIE_DOMAIN: ${NEXTAUTH_COOKIE_DOMAIN:-}
DATABASE_URL: postgresql://${POSTGRES_USER:-calcom}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-calcom}
DATABASE_DIRECT_URL: postgresql://${POSTGRES_USER:-calcom}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-calcom}
CALENDSO_ENCRYPTION_KEY: ${CALENDSO_ENCRYPTION_KEY}