fix: Implement unified authentication system
- Created single auth-unified.ts module as the source of truth - Deprecated old auth.ts and simple-auth.ts (now proxy to unified) - Fixed dashboard SSR auth using Astro.cookies for better compatibility - Added comprehensive auth test page at /auth-test-unified - Resolved cookie handling issues in Docker environment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
202
src/pages/auth-test-unified.astro
Normal file
202
src/pages/auth-test-unified.astro
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { verifyAuth, authDebug } from '../lib/auth-unified';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
// Test authentication
|
||||
let auth = null;
|
||||
let authError = null;
|
||||
let cookies = null;
|
||||
let headers = null;
|
||||
|
||||
try {
|
||||
// Test unified auth
|
||||
auth = await verifyAuth(Astro.request);
|
||||
|
||||
// Capture debug info
|
||||
cookies = Astro.request.headers.get('Cookie') || 'No cookies';
|
||||
headers = {
|
||||
'Authorization': Astro.request.headers.get('Authorization') || 'Not set',
|
||||
'User-Agent': Astro.request.headers.get('User-Agent') || 'Not set',
|
||||
'X-Forwarded-For': Astro.request.headers.get('X-Forwarded-For') || 'Not set'
|
||||
};
|
||||
|
||||
// Use debug utilities in development
|
||||
if (import.meta.env.DEV) {
|
||||
authDebug.logCookies(Astro.request);
|
||||
authDebug.logSession(auth?.session || null);
|
||||
}
|
||||
} catch (error) {
|
||||
authError = error instanceof Error ? error.message : 'Unknown error';
|
||||
}
|
||||
---
|
||||
|
||||
<Layout title="Unified Auth Test">
|
||||
<div class="min-h-screen bg-gray-100 p-8">
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-8">Unified Authentication System Test</h1>
|
||||
|
||||
<!-- Auth Status Card -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<h2 class="text-xl font-semibold mb-4">Authentication Status</h2>
|
||||
|
||||
{auth ? (
|
||||
<div class="space-y-4">
|
||||
<div class="p-4 bg-green-100 border border-green-400 rounded">
|
||||
<h3 class="font-semibold text-green-800">✅ Authenticated</h3>
|
||||
<div class="mt-2 space-y-1 text-sm">
|
||||
<p><strong>User ID:</strong> <code class="bg-gray-100 px-1">{auth.user.id}</code></p>
|
||||
<p><strong>Email:</strong> <code class="bg-gray-100 px-1">{auth.user.email}</code></p>
|
||||
<p><strong>Is Admin:</strong> <span class={auth.isAdmin ? 'text-green-600 font-semibold' : 'text-gray-600'}>{auth.isAdmin ? 'Yes' : 'No'}</span></p>
|
||||
<p><strong>Is Super Admin:</strong> <span class={auth.isSuperAdmin ? 'text-purple-600 font-semibold' : 'text-gray-600'}>{auth.isSuperAdmin ? 'Yes' : 'No'}</span></p>
|
||||
<p><strong>Organization ID:</strong> <code class="bg-gray-100 px-1">{auth.organizationId || 'None'}</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session Info -->
|
||||
<div class="p-4 bg-blue-50 border border-blue-200 rounded">
|
||||
<h3 class="font-semibold text-blue-800">Session Information</h3>
|
||||
<div class="mt-2 space-y-1 text-sm">
|
||||
<p><strong>Token Type:</strong> {auth.session.token_type}</p>
|
||||
<p><strong>Expires At:</strong> {new Date((auth.session.expires_at || 0) * 1000).toLocaleString()}</p>
|
||||
<p><strong>Access Token:</strong> <code class="bg-gray-100 px-1 text-xs">{auth.session.access_token.substring(0, 20)}...</code></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<a href="/dashboard" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
|
||||
User Dashboard
|
||||
</a>
|
||||
{auth.isAdmin && (
|
||||
<a href="/admin/dashboard" class="bg-purple-500 text-white px-4 py-2 rounded hover:bg-purple-600">
|
||||
Admin Dashboard
|
||||
</a>
|
||||
)}
|
||||
{auth.isSuperAdmin && (
|
||||
<a href="/admin/super-dashboard" class="bg-red-500 text-white px-4 py-2 rounded hover:bg-red-600">
|
||||
Super Dashboard
|
||||
</a>
|
||||
)}
|
||||
<a href="/api/auth/session" target="_blank" class="bg-gray-500 text-white px-4 py-2 rounded hover:bg-gray-600">
|
||||
Check Session API
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div class="space-y-4">
|
||||
<div class="p-4 bg-red-100 border border-red-400 rounded">
|
||||
<h3 class="font-semibold text-red-800">❌ Not Authenticated</h3>
|
||||
<p class="mt-2">You are not logged in or your session has expired.</p>
|
||||
{authError && (
|
||||
<p class="mt-2"><strong>Error:</strong> <code class="bg-red-50 px-1">{authError}</code></p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<a href="/login" class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
|
||||
Login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<!-- Request Debug Info -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<h2 class="text-xl font-semibold mb-4">Request Debug Information</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Cookies -->
|
||||
<div class="p-4 bg-gray-50 rounded">
|
||||
<h3 class="font-semibold mb-2">Cookies</h3>
|
||||
<pre class="text-xs bg-gray-100 p-2 rounded overflow-x-auto">{cookies}</pre>
|
||||
</div>
|
||||
|
||||
<!-- Headers -->
|
||||
<div class="p-4 bg-gray-50 rounded">
|
||||
<h3 class="font-semibold mb-2">Relevant Headers</h3>
|
||||
<pre class="text-xs bg-gray-100 p-2 rounded overflow-x-auto">{JSON.stringify(headers, null, 2)}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Test Actions -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
|
||||
<h2 class="text-xl font-semibold mb-4">Test Actions</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="p-4 border rounded">
|
||||
<h3 class="font-semibold mb-2">Test Protected Routes</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<p><a href="/dashboard" class="text-blue-600 hover:underline">→ Dashboard (requires auth)</a></p>
|
||||
<p><a href="/events/new" class="text-blue-600 hover:underline">→ New Event (requires auth)</a></p>
|
||||
<p><a href="/scan" class="text-blue-600 hover:underline">→ Scanner (requires auth)</a></p>
|
||||
<p><a href="/calendar" class="text-blue-600 hover:underline">→ Calendar (requires auth)</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded">
|
||||
<h3 class="font-semibold mb-2">Test Auth APIs</h3>
|
||||
<div class="space-y-2 text-sm">
|
||||
<p><a href="/api/auth/session" target="_blank" class="text-blue-600 hover:underline">→ Session API</a></p>
|
||||
<p><a href="/api/auth/logout" class="text-blue-600 hover:underline">→ Logout</a></p>
|
||||
<p><a href="/auth-test" class="text-blue-600 hover:underline">→ Old Auth Test (for comparison)</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auth System Info -->
|
||||
<div class="bg-white rounded-lg shadow-lg p-6">
|
||||
<h2 class="text-xl font-semibold mb-4">Unified Auth System Information</h2>
|
||||
|
||||
<div class="prose prose-sm max-w-none">
|
||||
<h3 class="text-lg font-semibold">Features</h3>
|
||||
<ul>
|
||||
<li>✅ Single source of truth for authentication</li>
|
||||
<li>✅ Works with both Request objects and AstroCookies</li>
|
||||
<li>✅ Supabase SSR integration</li>
|
||||
<li>✅ Bearer token fallback support</li>
|
||||
<li>✅ Role-based access control (User/Admin/Super Admin)</li>
|
||||
<li>✅ Organization-based access control</li>
|
||||
<li>✅ Security logging and rate limiting</li>
|
||||
<li>✅ Type-safe auth context</li>
|
||||
</ul>
|
||||
|
||||
<h3 class="text-lg font-semibold mt-4">Usage</h3>
|
||||
<pre class="bg-gray-100 p-3 rounded text-xs overflow-x-auto">
|
||||
// In Astro pages
|
||||
import { verifyAuth, requireAuth } from '../lib/auth-unified';
|
||||
|
||||
// Check auth (returns null if not authenticated)
|
||||
const auth = await verifyAuth(Astro.request);
|
||||
|
||||
// Require auth (throws if not authenticated)
|
||||
const auth = await requireAuth(Astro.request);
|
||||
|
||||
// Require admin
|
||||
const auth = await requireAdmin(Astro.request);
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<script>
|
||||
// Client-side session check
|
||||
async function checkClientSession() {
|
||||
try {
|
||||
const response = await fetch('/api/auth/session');
|
||||
const data = await response.json();
|
||||
console.log('[Client] Session check:', data);
|
||||
} catch (error) {
|
||||
console.error('[Client] Session check failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Check session on page load
|
||||
checkClientSession();
|
||||
</script>
|
||||
Reference in New Issue
Block a user