fix: Remove client-side auth from ProtectedRoute causing redirect loops
- Disabled client-side auth checks in ProtectedRoute component - Added server-side auth to onboarding/organization.astro - ProtectedRoute now acts as simple wrapper, auth handled server-side - Resolves setup screen → home redirect loop issue 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
---
|
||||
// Simple protected route component
|
||||
// DEPRECATED: Protected route component - now handled server-side
|
||||
// This component no longer performs authentication checks.
|
||||
// All authentication is handled by the unified auth system at the server level.
|
||||
|
||||
export interface Props {
|
||||
title?: string;
|
||||
requireAdmin?: boolean;
|
||||
@@ -8,135 +11,13 @@ export interface Props {
|
||||
const { title = "Protected Page", requireAdmin = false } = Astro.props;
|
||||
---
|
||||
|
||||
<!-- Simple wrapper - auth is handled server-side by unified auth system -->
|
||||
<div class="auth-wrapper">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { supabase } from '../lib/supabase';
|
||||
|
||||
// State tracking to prevent loops
|
||||
let authVerificationInProgress = false;
|
||||
let redirectInProgress = false;
|
||||
|
||||
console.log('[PROTECTED] ProtectedRoute mounted on:', window.location.pathname);
|
||||
|
||||
// Safe redirect with loop prevention
|
||||
function safeRedirectToLogin() {
|
||||
if (redirectInProgress) {
|
||||
console.log('[PROTECTED] Redirect already in progress, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't redirect if we're already on login page
|
||||
if (window.location.pathname === '/login') {
|
||||
console.log('[PROTECTED] Already on login page, not redirecting');
|
||||
return;
|
||||
}
|
||||
|
||||
redirectInProgress = true;
|
||||
console.log('[PROTECTED] Redirecting to login...');
|
||||
|
||||
setTimeout(() => {
|
||||
const returnTo = encodeURIComponent(window.location.pathname);
|
||||
window.location.href = `/login?returnTo=${returnTo}`;
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Enhanced auth verification with timeout and retry logic
|
||||
async function verifyAuth() {
|
||||
if (authVerificationInProgress) {
|
||||
console.log('[PROTECTED] Auth verification already in progress');
|
||||
return;
|
||||
}
|
||||
|
||||
authVerificationInProgress = true;
|
||||
console.log('[PROTECTED] Starting auth verification...');
|
||||
|
||||
try {
|
||||
// Add timeout to prevent hanging
|
||||
const authPromise = supabase.auth.getSession();
|
||||
const timeoutPromise = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('Auth verification timeout')), 8000)
|
||||
);
|
||||
|
||||
const { data: { session }, error } = await Promise.race([authPromise, timeoutPromise]) as any;
|
||||
|
||||
if (error) {
|
||||
console.warn('[PROTECTED] Auth verification failed:', error.message);
|
||||
safeRedirectToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
console.warn('[PROTECTED] No session found, redirecting to login');
|
||||
safeRedirectToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[PROTECTED] Auth verification successful');
|
||||
|
||||
// Store auth token for API calls
|
||||
const authToken = session.access_token;
|
||||
if (authToken) {
|
||||
// Set default authorization header for fetch requests
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = function(url, options = {}) {
|
||||
if (!options.headers) {
|
||||
options.headers = {};
|
||||
}
|
||||
|
||||
// Add auth header and credentials to API calls
|
||||
if (typeof url === 'string' && url.startsWith('/api/')) {
|
||||
options.headers['Authorization'] = `Bearer ${authToken}`;
|
||||
options.credentials = 'include';
|
||||
}
|
||||
|
||||
return originalFetch(url, options);
|
||||
};
|
||||
}
|
||||
|
||||
authVerificationInProgress = false;
|
||||
} catch (error) {
|
||||
console.error('[PROTECTED] Auth verification error:', error);
|
||||
authVerificationInProgress = false;
|
||||
safeRedirectToLogin();
|
||||
}
|
||||
}
|
||||
|
||||
// Delayed auth verification to prevent race conditions
|
||||
setTimeout(() => {
|
||||
verifyAuth();
|
||||
}, 200);
|
||||
|
||||
// Listen for auth state changes with debouncing
|
||||
let authChangeTimeout: number | null = null;
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
console.log('[PROTECTED] Auth state change:', event);
|
||||
|
||||
// Clear previous timeout
|
||||
if (authChangeTimeout) {
|
||||
clearTimeout(authChangeTimeout);
|
||||
}
|
||||
|
||||
// Debounce auth state changes
|
||||
authChangeTimeout = setTimeout(() => {
|
||||
if (event === 'SIGNED_OUT' || !session) {
|
||||
console.log('[PROTECTED] User signed out, redirecting to login');
|
||||
safeRedirectToLogin();
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.auth-wrapper {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Add loading state styles */
|
||||
.auth-loading {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
// Note: Authentication is now handled server-side by the unified auth system.
|
||||
// This component is kept for backwards compatibility but no longer performs auth checks.
|
||||
console.log('[PROTECTED] ProtectedRoute mounted - auth handled server-side');
|
||||
</script>
|
||||
@@ -1,6 +1,16 @@
|
||||
---
|
||||
import SecureLayout from '../../layouts/SecureLayout.astro';
|
||||
import ProtectedRoute from '../../components/ProtectedRoute.astro';
|
||||
import { verifyAuth } from '../../lib/auth-unified';
|
||||
|
||||
// Enable server-side rendering for auth checks
|
||||
export const prerender = false;
|
||||
|
||||
// Server-side authentication check
|
||||
const auth = await verifyAuth(Astro.cookies);
|
||||
if (!auth) {
|
||||
return Astro.redirect('/login');
|
||||
}
|
||||
---
|
||||
|
||||
<ProtectedRoute>
|
||||
|
||||
Reference in New Issue
Block a user