116 lines
3.2 KiB
TypeScript
116 lines
3.2 KiB
TypeScript
import { writable, derived } from 'svelte/store';
|
|
import type { User } from 'oidc-client-ts';
|
|
import { userManager, isOidcConfigured } from './oidcConfig';
|
|
|
|
// Stores
|
|
export const user = writable<User | null>(null);
|
|
export const isLoading = writable(true);
|
|
export const isAuthenticated = derived(user, ($user) => $user !== null);
|
|
export const isConfigured = isOidcConfigured;
|
|
|
|
// Cookie management
|
|
function setCookieFromUser(u: User) {
|
|
if (!u?.access_token) return;
|
|
|
|
const isProduction = window.location.hostname !== 'localhost';
|
|
const domain = isProduction ? '.orfl.xyz' : undefined;
|
|
const secure = isProduction;
|
|
const sameSite = isProduction ? 'None' : 'Lax';
|
|
|
|
const cookieValue = `fa_session=${u.access_token}; path=/; ${secure ? 'secure; ' : ''}samesite=${sameSite}${domain ? `; domain=${domain}` : ''}`;
|
|
document.cookie = cookieValue;
|
|
}
|
|
|
|
function clearFaSessionCookie() {
|
|
const isProduction = window.location.hostname !== 'localhost';
|
|
const domain = isProduction ? '.orfl.xyz' : undefined;
|
|
|
|
const cookieValue = `fa_session=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT${domain ? `; domain=${domain}` : ''}`;
|
|
document.cookie = cookieValue;
|
|
}
|
|
|
|
// Track if callback has been handled to prevent double processing
|
|
let callbackHandled = false;
|
|
|
|
export async function initAuth() {
|
|
if (!userManager) {
|
|
isLoading.set(false);
|
|
return;
|
|
}
|
|
|
|
// Handle callback if auth params are present
|
|
const url = new URL(window.location.href);
|
|
const hasAuthParams =
|
|
url.searchParams.has('code') ||
|
|
url.searchParams.has('id_token') ||
|
|
url.searchParams.has('error');
|
|
|
|
if (hasAuthParams && !callbackHandled) {
|
|
callbackHandled = true;
|
|
try {
|
|
const result = await userManager.signinRedirectCallback();
|
|
user.set(result ?? null);
|
|
if (result) {
|
|
setCookieFromUser(result);
|
|
}
|
|
} catch (e) {
|
|
console.error('Failed to complete sign-in redirect', e);
|
|
} finally {
|
|
const cleanUrl = `${url.origin}${url.pathname}`;
|
|
window.history.replaceState({}, document.title, cleanUrl);
|
|
}
|
|
}
|
|
|
|
// Load existing user
|
|
try {
|
|
const loadedUser = await userManager.getUser();
|
|
user.set(loadedUser ?? null);
|
|
if (loadedUser) {
|
|
setCookieFromUser(loadedUser);
|
|
}
|
|
} catch (e) {
|
|
console.error('Failed to load user', e);
|
|
}
|
|
|
|
isLoading.set(false);
|
|
|
|
// Event listeners
|
|
userManager.events.addUserLoaded((u) => {
|
|
user.set(u);
|
|
setCookieFromUser(u);
|
|
});
|
|
|
|
userManager.events.addUserUnloaded(() => {
|
|
user.set(null);
|
|
clearFaSessionCookie();
|
|
});
|
|
|
|
userManager.events.addUserSignedOut(() => {
|
|
user.set(null);
|
|
clearFaSessionCookie();
|
|
});
|
|
}
|
|
|
|
export async function login() {
|
|
if (!userManager) {
|
|
console.warn('OIDC is not configured; set PUBLIC_OIDC_* environment variables.');
|
|
return;
|
|
}
|
|
await userManager.signinRedirect();
|
|
}
|
|
|
|
export async function logout() {
|
|
if (!userManager) {
|
|
console.warn('OIDC is not configured; set PUBLIC_OIDC_* environment variables.');
|
|
return;
|
|
}
|
|
try {
|
|
clearFaSessionCookie();
|
|
await userManager.signoutRedirect();
|
|
} catch (error) {
|
|
console.error('Failed to sign out via redirect, clearing local session instead.', error);
|
|
await userManager.removeUser();
|
|
user.set(null);
|
|
}
|
|
}
|