Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions src/lib/client/stores/auth.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,31 @@ async function register(
}
}

function logout(): void {
async function logout(): Promise<void> {
state.user = null;
state.credits = null;
saveCachedAuth(null, null);
setActiveUserId(null);
// Clear local session cookie by setting expired
document.cookie = 'graphini_session=; Path=/; Max-Age=0';
window.location.href = '/api/auth/logout';

// POST clears both graphini_session and graphini_guest_id server-side, then
// 302s to /. We don't follow that redirect via fetch (browsers won't apply
// its Set-Cookie to the document anyway when fetch follows redirects), so
// we read the response and force-navigate to / ourselves below. The
// Set-Cookie on the POST response is what actually removes the cookies.
//
// The earlier `window.location.href = '/api/auth/logout'` issued a GET,
// which routes to magnova-auth's federated signout — wrong for guests
// (they have no magnova session) and unnecessary for password users.
try {
await fetch('/api/auth/logout', {
method: 'POST',
credentials: 'include',
redirect: 'manual'
});
} catch {
/* non-fatal — client state is already cleared and we force-reload below. */
}
window.location.href = '/';
}

async function refreshCredits(): Promise<void> {
Expand Down
22 changes: 12 additions & 10 deletions src/routes/api/auth/logout/+server.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import { redirect } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { clearLocalSessionCookie, getSignoutUrl } from '$lib/server/auth';
import { clearGuestCookieHeader, clearLocalSessionCookie, getSignoutUrl } from '$lib/server/auth';

export const GET: RequestHandler = async () => {
// Clear local session cookie, then redirect to magnova-auth signout
// Federated (magnova-auth) signout flow. Reserved for OAuth users who
// want their upstream session terminated too. Local clients should use
// POST so guests and password-login users don't get bounced through an
// external auth provider that has no session for them.
throw redirect(302, getSignoutUrl());
};

export const POST: RequestHandler = async ({ url }) => {
// Local logout — clear graphini_session cookie and redirect to home
// Local logout — clears both the password-session cookie and the guest
// cookie. Either may be present (or both, if a guest was migrated into
// a real account mid-session); clearing both is idempotent.
const secureCookie = url.protocol === 'https:';
return new Response(null, {
status: 302,
headers: {
'Set-Cookie': clearLocalSessionCookie(secureCookie),
Location: '/'
}
});
const headers = new Headers({ Location: '/' });
headers.append('Set-Cookie', clearLocalSessionCookie(secureCookie));
headers.append('Set-Cookie', clearGuestCookieHeader(secureCookie));
return new Response(null, { status: 302, headers });
};
Loading