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 {
|
export interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
requireAdmin?: boolean;
|
requireAdmin?: boolean;
|
||||||
@@ -8,135 +11,13 @@ export interface Props {
|
|||||||
const { title = "Protected Page", requireAdmin = false } = Astro.props;
|
const { title = "Protected Page", requireAdmin = false } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!-- Simple wrapper - auth is handled server-side by unified auth system -->
|
||||||
<div class="auth-wrapper">
|
<div class="auth-wrapper">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { supabase } from '../lib/supabase';
|
// 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.
|
||||||
// State tracking to prevent loops
|
console.log('[PROTECTED] ProtectedRoute mounted - auth handled server-side');
|
||||||
let authVerificationInProgress = false;
|
</script>
|
||||||
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>
|
|
||||||
@@ -1,6 +1,16 @@
|
|||||||
---
|
---
|
||||||
import SecureLayout from '../../layouts/SecureLayout.astro';
|
import SecureLayout from '../../layouts/SecureLayout.astro';
|
||||||
import ProtectedRoute from '../../components/ProtectedRoute.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>
|
<ProtectedRoute>
|
||||||
|
|||||||
Reference in New Issue
Block a user