import { redirect } from '@sveltejs/kit'; import type { RequestHandler } from './$types'; import { kindeAuthClient, type SessionManager } from '@kinde-oss/kinde-auth-sveltekit'; import { getUsernameFromToken } from '$lib/kinde/auth-utils'; // Whitelist of allowed redirect paths for security const ALLOWED_REDIRECT_PATHS = [ '/', '/profile', ]; function isValidRedirectPath(path: string): boolean { // Must start with / and not contain dangerous characters if (!path.startsWith('/')) return false; if ( path.includes('//') || path.includes('\\') || path.includes('<') || path.includes('>') ) return false; // Check against whitelist return ALLOWED_REDIRECT_PATHS.some((allowed) => path.startsWith(allowed)); } export const GET: RequestHandler = async ({ request, url, cookies }) => { // Get the redirect target from query params with validation const rawRedirectTo = url.searchParams.get('redirect_to') || '/'; const redirectTo = isValidRedirectPath(rawRedirectTo) ? rawRedirectTo : '/'; // Store the redirect URL in a secure cookie cookies.set('post_refresh_redirect', redirectTo, { path: '/', httpOnly: true, // ✅ Prevent XSS access secure: url.protocol === 'https:', sameSite: 'lax', // ✅ Enhanced CSRF protection maxAge: 60 * 5 // 5 minutes }); // Check if user is authenticated const isAuthenticated = await kindeAuthClient.isAuthenticated( request as unknown as SessionManager ); if (!isAuthenticated) { // Directly redirect to login without silent auth attempt when not authenticated const loginUrl = new URL('/api/auth/login', url.origin); loginUrl.searchParams.set( 'post_login_redirect_url', new URL(redirectTo, url.origin).toString() ); return redirect(302, loginUrl.toString()); } // Get current user to check session validity const user = await kindeAuthClient.getUser( request as unknown as SessionManager ); // Log user information for debugging if (user) { // Get the custom username from user_properties const customUsername = await getUsernameFromToken(request as unknown as SessionManager); console.log('Session refresh attempt for user:', { id: user.id, email: user.email, custom_username: customUsername, given_name: user.given_name, family_name: user.family_name }); } // If no user or no valid session, redirect to login directly if (!user?.id) { const loginUrl = new URL('/api/auth/login', url.origin); loginUrl.searchParams.set( 'post_login_redirect_url', new URL(redirectTo, url.origin).toString() ); return redirect(302, loginUrl.toString()); } // Try to refresh user claims via Kinde management API try { const { getKindeManagementClient } = await import('$lib/kinde/server'); const managementClient = getKindeManagementClient(); await managementClient.refreshUserClaims(user.id); } catch (error) { console.error('Session refresh - failed to refresh claims via management API:', error); } // Check if the session token is still valid by verifying we can get the token try { const token = await kindeAuthClient.getToken( request as unknown as SessionManager ); // If we have a valid token, try silent refresh using prompt none if (token) { const kindeLoginUrl = new URL('/api/auth/login', url.origin); kindeLoginUrl.searchParams.set('prompt', 'none'); kindeLoginUrl.searchParams.set( 'post_login_redirect_url', new URL(redirectTo, url.origin).toString() ); return redirect(302, kindeLoginUrl.toString()); } } catch (error) { // Token is invalid or expired, need explicit login console.warn('Session token invalid, redirecting to login:', { message: error instanceof Error ? error.message : 'Unknown error', error: error }); } // If no valid token, redirect to regular login const loginUrl = new URL('/api/auth/login', url.origin); loginUrl.searchParams.set( 'post_login_redirect_url', new URL(redirectTo, url.origin).toString() ); return redirect(302, loginUrl.toString()); };