# Authentication System Documentation

## Overview

Black Canyon Tickets uses a unified authentication system built on top of Supabase Auth with server-side rendering (SSR) support. All authentication functionality is centralized in a single module (`src/lib/auth-unified.ts`) to ensure consistency and maintainability.

## Architecture

### Core Module: `auth-unified.ts`

The unified auth module is the single source of truth for all authentication in the application. It provides:

- 🔐 **Session-based authentication** using Supabase cookies
- 🎭 **Role-based access control** (User, Admin, Super Admin)
- 🏢 **Organization-based access control**
- 🛡️ **Security logging and rate limiting**
- 📝 **Type-safe authentication context**
- 🐳 **Docker-friendly cookie handling**

### Key Features

1. **Universal Compatibility**: Works with both `Request` objects (API routes) and `AstroCookies` (Astro pages)
2. **SSR Support**: Full server-side rendering support with proper cookie handling
3. **Bearer Token Fallback**: Supports Authorization header for API clients
4. **Security Hardening**: Built-in CSRF protection, rate limiting, and security logging
5. **Type Safety**: Full TypeScript support with proper types

## Usage Guide

### Basic Authentication Check

```typescript
// In Astro pages (.astro files)
import { verifyAuth } from '../lib/auth-unified';

// Check if user is authenticated (returns null if not)
const auth = await verifyAuth(Astro.cookies);

// In API routes (.ts files)
const auth = await verifyAuth(request);
```

### Requiring Authentication

```typescript
// Throws AuthError if not authenticated
const auth = await requireAuth(Astro.cookies);

// The auth object contains:
// - user: Supabase user object
// - session: Session information
// - isAdmin: boolean
// - isSuperAdmin: boolean
// - organizationId: string | null
```

### Role-Based Access Control

```typescript
// Require admin access
const auth = await requireAdmin(Astro.cookies);

// Require super admin access
const auth = await requireSuperAdmin(Astro.cookies);

// Check organization access
const auth = await requireOrganizationAccess(Astro.cookies, organizationId);
```

### Protected Page Pattern

```typescript
---
import Layout from '../layouts/Layout.astro';
import { verifyAuth } from '../lib/auth-unified';

export const prerender = false; // Enable SSR

const auth = await verifyAuth(Astro.cookies);
if (!auth) {
  return Astro.redirect('/login');
}
---

<Layout title="Protected Page">
  <h1>Welcome, {auth.user.email}!</h1>
</Layout>
```

### Protected API Route Pattern

```typescript
import type { APIRoute } from 'astro';
import { requireAuth, createAuthResponse } from '../lib/auth-unified';

export const GET: APIRoute = async ({ request }) => {
  try {
    const auth = await requireAuth(request);
    
    // Your protected logic here
    const data = { userId: auth.user.id };
    
    return createAuthResponse(data);
  } catch (error) {
    return createAuthResponse(
      { error: error.message },
      error.statusCode || 401
    );
  }
};
```

### Using the Middleware Pattern

```typescript
import { withAuth } from '../lib/auth-unified';

// Wrap your handler with authentication
export const GET: APIRoute = async ({ request }) => {
  return withAuth(request, async (auth) => {
    // This code only runs if authenticated
    return new Response(JSON.stringify({
      message: `Hello ${auth.user.email}`
    }));
  });
};
```

## Authentication Flow

1. **Login**: User submits credentials → `/api/auth/login` → Supabase sets cookies → Redirect to dashboard
2. **Session Check**: Every request → `verifyAuth()` checks cookies → Returns auth context or null
3. **Protected Routes**: Page/API checks auth → Redirects to login or returns 401 if not authenticated
4. **Logout**: Clear session → `/api/auth/logout` → Supabase clears cookies → Redirect to login

## Error Handling

The auth system uses a custom `AuthError` class with specific error codes:

```typescript
try {
  const auth = await requireAuth(request);
} catch (error) {
  if (error instanceof AuthError) {
    switch (error.code) {
      case 'NO_SESSION':
        // User not logged in
        break;
      case 'NO_PERMISSION':
        // User lacks required role
        break;
      case 'EXPIRED':
        // Session expired
        break;
    }
  }
}
```

## Security Features

### CSRF Protection

```typescript
// Generate token for forms
const csrfToken = generateCSRFToken();

// Verify token on submission
if (!verifyCSRFToken(request, sessionToken)) {
  throw new Error('Invalid CSRF token');
}
```

### Rate Limiting

```typescript
// Check rate limit (10 requests per minute by default)
const identifier = `login:${email}`;
if (!checkRateLimit(identifier, 5, 60000)) {
  throw new Error('Too many attempts');
}
```

### Security Logging

All authentication events are automatically logged:
- Failed login attempts
- Successful authentications
- Permission denied events
- Rate limit violations

## Testing

Visit `/auth-test-unified` to test the authentication system. This page shows:
- Current authentication status
- Session information
- Request headers and cookies
- Links to test protected routes

## Migration Guide

### From Old Auth System

1. **Update imports**:
   ```typescript
   // Old
   import { verifyAuth } from '../lib/auth';
   
   // New (but old path still works via proxy)
   import { verifyAuth } from '../lib/auth-unified';
   ```

2. **Use Astro.cookies instead of Astro.request**:
   ```typescript
   // Old
   const auth = await verifyAuth(Astro.request);
   
   // New (better SSR support)
   const auth = await verifyAuth(Astro.cookies);
   ```

3. **Handle new error types**:
   ```typescript
   // Old
   if (!auth) throw new Error('Not authenticated');
   
   // New
   import { AuthError } from '../lib/auth-unified';
   if (!auth) throw new AuthError('Not authenticated', 'NO_SESSION');
   ```

## Docker Considerations

The unified auth system is designed to work seamlessly in Docker environments:

1. **Cookie Domain**: Automatically handles cookie domain settings
2. **Secure Cookies**: Uses secure cookies in production
3. **Proxy Support**: Correctly reads IP addresses behind proxies

## Environment Variables

```bash
# Required for auth to work
PUBLIC_SUPABASE_URL=https://your-project.supabase.co
PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-key

# Optional for enhanced security
COOKIE_DOMAIN=.yourdomain.com  # For subdomain support
NODE_ENV=production            # Enables secure cookies
```

## Troubleshooting

### Common Issues

1. **"No session found" after login**
   - Check cookie settings in browser
   - Verify Supabase URL and keys are correct
   - Ensure cookies are not blocked

2. **Dashboard flashing before redirect**
   - Ensure using `Astro.cookies` not `Astro.request`
   - Verify `prerender = false` is set
   - Check server-side auth is enabled

3. **Auth works locally but not in Docker**
   - Check `COOKIE_DOMAIN` environment variable
   - Verify proxy headers are being forwarded
   - Ensure secure cookie settings match environment

### Debug Mode

Enable debug logging in development:

```typescript
// In your page or API route
import { authDebug } from '../lib/auth-unified';

authDebug.logCookies(request);
authDebug.logSession(session);
```

## Best Practices

1. **Always use the unified auth module** - Don't create separate auth implementations
2. **Use `Astro.cookies` for pages** - Better SSR support than `Astro.request`
3. **Handle errors gracefully** - Show user-friendly messages, not technical errors
4. **Test auth flows regularly** - Use `/auth-test-unified` to verify functionality
5. **Keep sessions secure** - Use HTTPS in production, set proper cookie flags

## Future Enhancements

- [ ] Refresh token rotation
- [ ] Remember me functionality
- [ ] Two-factor authentication
- [ ] Session activity tracking
- [ ] IP-based session validation