# FastHTML + FastAPI Authentication Integration

This package provides a complete authentication system integrating FastHTML (frontend) with FastAPI (backend).

## Architecture

```
auth/
├── __init__.py              # Package initialization
├── utils.py                 # JWT helpers + Beforeware
├── pages/
│   ├── __init__.py
│   ├── LoginPage.py         # Login form component
│   ├── RegisterPage.py      # Registration form component
│   └── WelcomePage.py       # Protected welcome page
└── routes.py                # All routes (public + protected)
```

## Features

- ✅ **Login page** with email/password authentication
- ✅ **Registration page** with password confirmation
- ✅ **Automatic token refresh** (proactive refresh at 5 minutes before expiry)
- ✅ **Route protection** with Beforeware (whitelist support)
- ✅ **Session management** using FastHTML signed cookies
- ✅ **DaisyUI 5** components for beautiful UI
- ✅ **HTMX integration** for dynamic form submissions

## Dependencies

Install the required packages:

```bash
pip install fasthtml httpx python-jose[cryptography] --break-system-packages
```

Note: `python-jose` may already be installed if you have FastAPI.

## Configuration

### 1. Update API configuration in `auth/utils.py`

```python
API_BASE_URL = "http://localhost:5001"  # Your FastAPI backend URL
JWT_SECRET = "jwt-secret-to-change"     # Must match your FastAPI secret
```

### 2. Create your `main.py`

```python
from fasthtml.common import fast_app, serve, Link, Script
from auth import create_auth_beforeware, setup_auth_routes

# Import your existing FastAPI auth app
# from your_auth_module import create_auth_app_for_sqlite

# Create Beforeware for route protection
beforeware = create_auth_beforeware()

# Create FastHTML app
app, rt = fast_app(
    before=beforeware,
    hdrs=(
        # DaisyUI 5 CSS
        Link(rel='stylesheet', href='https://cdn.jsdelivr.net/npm/daisyui@5/daisyui.css'),
        # Tailwind CSS 4
        Script(src='https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4'),
    )
)

# Mount FastAPI auth backend
# auth_api = create_auth_app_for_sqlite("Users.db", "jwt-secret-to-change")
# app.mount("/auth", auth_api)

# Setup authentication routes
setup_auth_routes(app, rt)

if __name__ == "__main__":
    serve()
```

## Usage

### Starting the application

```bash
python main.py
```

The application will be available at `http://localhost:5001`.

### Routes

**Public routes:**
- `GET /login` - Display login page
- `POST /login` - Handle login submission
- `GET /register` - Display registration page
- `POST /register` - Handle registration submission

**Protected routes (require authentication):**
- `GET /` - Welcome page (home)
- `GET /welcome` - Alternative welcome page
- `POST /logout` - Logout and revoke tokens

### Adding custom protected routes

```python
@rt("/dashboard")
def get_dashboard(session, auth):
    """
    Custom protected route.
    
    The 'auth' parameter is automatically injected by the Beforeware.
    """
    user_info = session.get('user_info', {})
    return Div(
        H1(f"Dashboard for {user_info.get('email', 'User')}"),
        # Your dashboard content
    )
```

### Extending the whitelist

If you need to add more public routes:

```python
beforeware = create_auth_beforeware(
    additional_patterns=[
        '/about',
        '/contact',
        r'/api/.*',  # Regex patterns are supported
    ]
)
```

## How it works

### 1. Beforeware Protection

The `auth_before()` function runs before every route (except whitelisted ones):

1. Checks if `access_token` exists in session
2. Validates token expiration
3. If token expires in < 5 minutes, automatically refreshes it
4. If refresh fails or no token exists, redirects to `/login`

### 2. Token Refresh Flow

```
User Request → Beforeware checks token
                ↓
         Token expires in < 5 min?
                ↓ Yes
         Call /auth/refresh with refresh_token
                ↓
         Update session with new tokens
                ↓
         Continue to route handler
```

### 3. Session Storage

Session contains:
- `access_token` (JWT, 30 minutes validity)
- `refresh_token` (Opaque, 7 days validity)
- `user_info` (email, id, etc.)

## Customization

### Changing the refresh threshold

Edit `auth/utils.py`:

```python
TOKEN_REFRESH_THRESHOLD_MINUTES = 5  # Change to your preferred value
```

### Customizing page components

Each page component is a class with:
- `__init__()` - Constructor with parameters
- `_render()` - HTML generation logic
- `__ft__()` - FastHTML protocol method

Example:

```python
class LoginPage:
    def __init__(self, error_message=None, redirect_url="/"):
        self.error_message = error_message
        self.redirect_url = redirect_url
    
    def _render(self):
        # Build your custom HTML here
        return Div(...)
    
    def __ft__(self):
        return self._render()
```

### Styling with DaisyUI 5

DaisyUI 5 provides semantic class names:

```python
# Button
Button("Click me", cls="btn btn-primary")

# Input
Input(type="email", cls="input input-bordered")

# Card
Div(
    Div(
        H2("Title", cls="card-title"),
        P("Content"),
        cls="card-body"
    ),
    cls="card bg-base-100 shadow-xl"
)

# Alert
Div(
    Span("Success message"),
    cls="alert alert-success"
)
```

## Troubleshooting

### Issue: "Module not found: auth"

Make sure the `auth` directory is in your Python path or in the same directory as `main.py`.

### Issue: "Connection refused" when calling API

Check that:
1. `API_BASE_URL` in `auth/utils.py` matches your FastAPI server
2. Your FastAPI backend is running
3. The `/auth` endpoints are correctly mounted

### Issue: Token refresh not working

Verify:
1. `JWT_SECRET` in `auth/utils.py` matches your FastAPI secret
2. Your FastAPI `/auth/refresh` endpoint is working
3. The refresh token is being stored correctly in the session

### Issue: Infinite redirect loop

Check:
1. The `/login` route is in the whitelist (it should be by default)
2. Your FastAPI `/auth/login` endpoint returns `access_token` and `refresh_token`

## Testing

To test the authentication flow:

1. Start your application
2. Navigate to `http://localhost:5001/`
3. You should be redirected to `/login`
4. Register a new account at `/register`
5. Login with your credentials
6. You should see the welcome page
7. Your session will automatically refresh tokens as needed

## API Integration

This package expects your FastAPI backend to provide these endpoints:

- `POST /auth/login` - Returns `access_token` and `refresh_token`
- `POST /auth/register` - Creates a new user
- `POST /auth/refresh` - Refreshes the access token
- `GET /auth/me` - Returns current user info (requires Bearer token)
- `POST /auth/logout` - Revokes refresh token

## License

This code is provided as-is for educational and development purposes.

## Questions?

Feel free to modify and extend this authentication system according to your needs!