Production HTTPS and HTTP/2¶
TLS termination and HTTP/2 for browsers are handled outside this application by infrastructure provisioned with Terraform (not in this repo).
Request path¶
Browser --HTTPS (HTTP/2 or HTTP/1.1)--> ALB (ACM certificate)
--HTTP/1.1--> Nginx on EB instance (port 80)
--HTTP/1.1--> Uvicorn / FastAPI (127.0.0.1:8000)
- HTTP/2 and HTTP/1.1 fallback are negotiated by the Application Load Balancer on the HTTPS listener. No application code is required.
- Uvicorn and instance Nginx stay on plain HTTP/1.1. Do not add
listen 443or certificates on the EC2 instance unless you intentionally change the architecture.
Terraform responsibilities¶
| Resource | Purpose |
|---|---|
| ACM | TLS certificate for the public hostname (same region as the ALB) |
| Route 53 | A / AAAA alias to the Elastic Beanstalk environment load balancer |
| ALB | HTTPS listener on 443 with the ACM cert; optional HTTP 80 → redirect to 443 |
| EB environment | App deploy target; set env vars (see below) |
After apply, the public API base URL should look like: https://api.example.com.
Application configuration (EB env / secrets)¶
Set on the EB environment (via Terraform or console):
| Variable | Example | Notes |
|---|---|---|
AUTH_COOKIE_SECURE |
true |
Required so access_token cookies are Secure over HTTPS |
AUTH_COOKIE_SAMESITE |
lax |
Default; adjust if cross-site frontend |
OAUTH_REDIRECT_BASE_URL |
https://api.example.com |
OAuth callback host (API, not SPA) |
FRONTEND_URL |
https://app.example.com |
CORS and post-login redirect |
OAUTH_GOOGLE_CLIENT_ID / SECRET |
(from Google Cloud console) | Social login |
OAUTH_GITHUB_CLIENT_ID / SECRET |
(from GitHub OAuth app) | Social login |
OAuth redirect URIs (provider consoles)¶
Register these against your public HTTPS API host:
https://<api-host>/api/auth/oauth/google/callbackhttps://<api-host>/api/auth/oauth/github/callback
Verification¶
# HTTP/2 (if curl supports it)
curl -I --http2 https://<api-host>/api/health
# HTTP/1.1 fallback on same URL
curl -I --http1.1 https://<api-host>/api/health
Optional instance Nginx tweaks¶
Only if cookies or redirects show http incorrectly, or SSE streams stall:
- Forward
X-Forwarded-Protofrom the ALB proxy_buffering offon/api/for streaming
See .ebextensions/00_ami.config for the current Nginx template.
Local OAuth development (Vite + GitHub)¶
OAuth state is stored in a session cookie on the API host. Vite’s dev proxy does not reliably forward that cookie, so local GitHub login uses the API origin for the OAuth redirect, then a one-time handoff back to Vue.
Checklist¶
| Item | Local example |
|---|---|
| Browser (chat UI) | http://127.0.0.1:5173 |
FRONTEND_URL |
http://127.0.0.1:5173 |
OAUTH_REDIRECT_BASE_URL |
http://127.0.0.1:8000 (API, not :5173) |
frontend-vue/.env.local |
VITE_OAUTH_API_URL=http://127.0.0.1:8000 |
| GitHub OAuth app callback | http://127.0.0.1:8000/api/auth/oauth/github/callback |
Flow: user clicks GitHub on Vue → browser hits :8000 for OAuth → GitHub callback on :8000 → API redirects to http://127.0.0.1:5173/oauth/handoff?code=... → Vue exchanges code for JWT cookies.
localhost and 127.0.0.1 are different hosts for cookies. Use 127.0.0.1 everywhere if Vite binds to it (see scripts/run-frontend-vue.sh).
Restart the API after changing .env. Start a new OAuth flow after an error (do not refresh the callback URL).
Symptom → fix¶
| Symptom | Likely cause | Fix |
|---|---|---|
MismatchingStateError / mismatching_state |
Mixed localhost / 127.0.0.1, or callback on wrong port |
Align checklist above; callback on :8000 |
| Same error on refresh | OAuth code/state already used or session missing |
Open /login and try GitHub again once |
503 on /api/auth/oauth/github |
Missing OAUTH_* credentials |
Set client id/secret in .env and restart API |
Verify: ./scripts/verify_oauth.py (repo root, venv active).
Out of scope in this repo¶
- Terraform modules for Route 53, ACM, or ALB
- Local mkcert / dev HTTP/2 proxy (use plain
http://127.0.0.1:8000for daily dev unless you add a proxy yourself)