# M1.2 — CORS Middleware Setup Documentation

This document explains the Cross-Origin Resource Sharing (CORS) setup implemented in Milestone 1.2 for the Universal Chatbot Widget backend.

---

## 1. What is CORS?

**CORS (Cross-Origin Resource Sharing)** is a browser security mechanism that controls whether web applications running at one **Origin** (domain/protocol/port) are allowed to access resources served by an API running at a different **Origin**.

By default, web browsers enforce the **Same-Origin Policy (SOP)**. Under SOP:
- A webpage served from `https://example.com` can freely make requests to `https://example.com/api`.
- A webpage served from `https://example.com` **CANNOT** read responses from `https://api.chatbot.com/api/v1/...` unless `https://api.chatbot.com` explicitly sends CORS approval HTTP response headers.

---

## 2. Why Does the Universal Chatbot Widget Need CORS?

The Universal Chatbot Widget script (`widget.js`) is designed to be embedded on arbitrary customer websites (e.g. `https://example.com`, `http://localhost:3000`, etc.).

When a visitor opens `https://example.com`, the browser executes the embedded widget script. That script sends asynchronous HTTP requests (`fetch` / `XHR`) back to our backend API at `https://api.chatbot.com`.

Because `https://example.com` and `https://api.chatbot.com` are different origins, the visitor's browser will block the widget from reading API responses unless our backend includes proper CORS response headers.

---

## 3. What Does `Origin` Mean?

An **Origin** is defined by three components:
1. **Protocol** (`http://` or `https://`)
2. **Domain/Host** (`example.com` or `localhost`)
3. **Port** (`:8000`, `:3000`, `:5500`, etc.)

If *any* of these three parts differ between the webpage and the API server, the request is considered **Cross-Origin**.

### Examples:
- `http://localhost:3000` and `http://localhost:8000` $\rightarrow$ **Different Origins** (different ports: 3000 vs 8000).
- `http://example.com` and `https://example.com` $\rightarrow$ **Different Origins** (different protocols: HTTP vs HTTPS).
- `https://app.example.com` and `https://example.com` $\rightarrow$ **Different Origins** (different subdomains).

---

## 4. Why `allow_origins=["*"]` is NOT Appropriate for This Project

Setting `allow_origins=["*"]` allows **ANY** website on the internet to send cross-origin requests to your backend API.

While convenient during early prototyping, `*` is bad for this project because:
1. **Security & Data Privacy:** Any malicious website could load your backend endpoints and execute requests against your tenants without origin restrictions.
2. **Multi-Tenancy Isolation:** In our architecture, every tenant registers their specific domain(s). Validating allowed origins ensures that requests only come from authorized customer domains.
3. **Credentials & Cookies:** Browsers prohibit sending authenticated requests with credentials (`allow_credentials=True`) if `allow_origins` is set to wildcard `*`.

---

## 5. How the Current M1.2 Configuration Works

In M1.2, we configured CORS via environment settings and FastAPI's native `CORSMiddleware`:

1. **Configuration (`app/config.py`):**
   - Added `allowed_origins: list[str] | str` to the `Settings` model.
   - Default local allowed origins: `["http://localhost:3000", "http://localhost:8000", "http://127.0.0.1:5500", "http://127.0.0.1:8000"]`.
   - Included a `@field_validator` to parse comma-separated strings or JSON arrays provided via the `.env` file (`ALLOWED_ORIGINS=...`).

2. **Middleware Registration (`app/main.py`):**
   - Mounted Starlette's `CORSMiddleware` onto the FastAPI app instance:
     ```python
     app.add_middleware(
         CORSMiddleware,
         allow_origins=settings.allowed_origins,
         allow_credentials=True,
         allow_methods=["*"],
         allow_headers=["*"],
     )
     ```

---

## 6. Practical Example Walkthrough

### Scenario:
A visitor visits `https://example.com`. The embedded widget makes a request to `https://api.chatbot.com/api/v1/session/init`.

```text
Visitor Browser (at https://example.com)
     │
     │ 1. HTTP POST request sent with header:
     │    Origin: https://example.com
     ▼
Backend API (https://api.chatbot.com)
     │
     │ 2. CORSMiddleware inspects Origin header.
     │    Is "https://example.com" in settings.allowed_origins?
     │
     ├───────► YES: Backend returns HTTP Response + Header:
     │              Access-Control-Allow-Origin: https://example.com
     │              Access-Control-Allow-Credentials: true
     │              Browser allows widget script to read response!
     │
     └───────► NO:  Backend processes response WITHOUT Access-Control-Allow-Origin.
                    Browser blocks widget script from reading response data!
```

---

## 7. Files Changed in M1.2

- **[backend/app/config.py](file:///c:/Users/alokc/chatbot/backend/app/config.py):** Added `allowed_origins` configuration field and custom Pydantic validator.
- **[backend/app/main.py](file:///c:/Users/alokc/chatbot/backend/app/main.py):** Imported and added `CORSMiddleware` to FastAPI app.
- **[backend/.env](file:///c:/Users/alokc/chatbot/backend/.env) & [backend/.env.example](file:///c:/Users/alokc/chatbot/backend/.env.example):** Added `ALLOWED_ORIGINS` environment variable key.
- **[backend/tests/test_cors.py](file:///c:/Users/alokc/chatbot/backend/tests/test_cors.py):** Added unit tests verifying allowed origins, preflight requests, and disallowed origins.
