···9393 ```
949495953. Generate OAuth Keys
9696-```bash
9797-# Generate private key
9898-openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
9999-100100-# Extract public key
101101-openssl ec -in private-key.pem -pubout -out public-key.pem
102102-103103-# View private key (copy for .env)
104104-cat private-key.pem
105105-```
9696+ ```bash
9797+ # Generate private key
9898+ openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
9999+100100+ # Extract public key
101101+ openssl ec -in private-key.pem -pubout -out public-key.pem
102102+103103+ # View private key (copy for .env)
104104+ cat private-key.pem
105105+ ```
1061061071074. Extract Public Key JWK
108108-```bash
109109-node -e "
110110-const fs = require('fs');
111111-const jose = require('jose');
112112-const pem = fs.readFileSync('public-key.pem', 'utf8');
113113-jose.importSPKI(pem, 'ES256').then(key => {
114114- return jose.exportJWK(key);
115115-}).then(jwk => {
116116- console.log(JSON.stringify(jwk, null, 2));
117117-});
118118-"
119119-```
108108+ ```bash
109109+ node -e "
110110+ const fs = require('fs');
111111+ const jose = require('jose');
112112+ const pem = fs.readFileSync('public-key.pem', 'utf8');
113113+ jose.importSPKI(pem, 'ES256').then(key => {
114114+ return jose.exportJWK(key);
115115+ }).then(jwk => {
116116+ console.log(JSON.stringify(jwk, null, 2));
117117+ });
118118+ "
119119+ ```
1201201211215. Update netlify/functions/jwks.ts
122122···1241241251256. Create .env
126126127127-```bash
128128-VITE_LOCAL_MOCK=false
129129-VITE_API_BASE=/.netlify/functions
130130-131131-# Database (choose one)
132132-NETLIFY_DATABASE_URL=postgresql://user:pass@host/db # Neon
133133-# NETLIFY_DATABASE_URL=postgresql://localhost/atlast_dev # Local
134134-135135-# OAuth (paste your private key)
136136-OAUTH_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_KEY_HERE\n-----END PRIVATE KEY-----"
137137-138138-# Local URLs (MUST use 127.0.0.1 for OAuth)
139139-URL=http://127.0.0.1:8888
140140-DEPLOY_URL=http://127.0.0.1:8888
141141-DEPLOY_PRIME_URL=http://127.0.0.1:8888
142142-CONTEXT=dev
143143-```
127127+ ```bash
128128+ VITE_LOCAL_MOCK=false
129129+ VITE_API_BASE=/.netlify/functions
130130+131131+ # Database (choose one)
132132+ NETLIFY_DATABASE_URL=postgresql://user:pass@host/db # Neon
133133+ # NETLIFY_DATABASE_URL=postgresql://localhost/atlast_dev # Local
134134+135135+ # OAuth (paste your private key)
136136+ OAUTH_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nYOUR_KEY_HERE\n-----END PRIVATE KEY-----"
137137+138138+ # Local URLs (MUST use 127.0.0.1 for OAuth)
139139+ URL=http://127.0.0.1:8888
140140+ DEPLOY_URL=http://127.0.0.1:8888
141141+ DEPLOY_PRIME_URL=http://127.0.0.1:8888
142142+ CONTEXT=dev
143143+ ```
1441441451457. Initialize Database
146146-```bash
147147-pnpm run init-db
148148-```
146146+ ```bash
147147+ pnpm run init-db
148148+ ```
1491491501508. Start Development Server
151151-```bash
152152-npx netlify-cli dev --filter @atlast/web
153153-# Or use the alias:
154154-pnpm run dev
155155-```
151151+ ```bash
152152+ npx netlify-cli dev --filter @atlast/web
153153+ # Or use the alias:
154154+ pnpm run dev
155155+ ```
1561561571579. Test OAuth
158158
+10-10
docs/git-history.json
···11[
22 {
33- "hash": "15b67054a684ebb2a21761a1774ba15f9b1c29e2",
44- "short_hash": "15b6705",
33+ "hash": "18f4ca7017ea6ca5d959f5d9596690c17b171bc3",
44+ "short_hash": "18f4ca7",
55 "author": "Ariel M. Lighty",
66- "date": "2025-12-28T20:38:38-05:00",
77- "message": "fix: add health check function for extension server detection\n\n- Created /health function endpoint with CORS support\n- Updated checkServerHealth to use function endpoint instead of root URL\n- Fixes Firefox extension server detection with proper CORS headers",
88- "files_changed": 5
66+ "date": "2025-12-28T21:38:11-05:00",
77+ "message": "fix: pass event to errorResponse for proper CORS on errors\n\n- Error middleware now passes event parameter to errorResponse\n- Fixes Firefox extension CORS headers on authentication errors\n- Both withErrorHandling and withAuthErrorHandling updated\n- Extension origin properly reflected in all error responses",
88+ "files_changed": 3
99 },
1010 {
1111 "hash": "603cf0a187850664336a12c9e5cbb49038906f53",
···1616 "files_changed": 4
1717 },
1818 {
1919- "hash": "bd3aabb75abb1875aef125610fcdccb14967a8e3",
2020- "short_hash": "bd3aabb",
1919+ "hash": "603cf0a187850664336a12c9e5cbb49038906f53",
2020+ "short_hash": "603cf0a",
2121 "author": "Ariel M. Lighty",
2222- "date": "2025-12-27T22:10:11-05:00",
2323- "message": "fix: extension dark mode and build mode messaging\n\n- Changed darkMode from 'class' to 'media' for automatic system preference detection\n- Made server offline message conditional on build mode (dev vs prod)\n- Hide dev server instructions in production builds",
2424- "files_changed": 5
2222+ "date": "2025-12-27T22:42:43-05:00",
2323+ "message": "fix: CORS for extension credentialed requests\n\nUpdated CORS headers to support credentials from Chrome extensions:\n- Added getCorsHeaders() to detect chrome-extension:// origins\n- Changed from wildcard Access-Control-Allow-Origin to specific origin\n- Added Access-Control-Allow-Credentials: true for credentialed requests\n- Updated session endpoint to pass event for CORS header detection",
2424+ "files_changed": 4
2525 },
2626 {
2727 "hash": "bd3aabb75abb1875aef125610fcdccb14967a8e3",
+6-6
docs/graph-data.json
···43294329 "node_type": "observation",
43304330 "title": "CORS fully working - Firefox extension origin properly reflected with credentials. But cookies not sent from extension despite credentials:include. Cookie set in web context not accessible from extension context due to Firefox cookie partitioning.",
43314331 "description": null,
43324332- "status": "pending",
43324332+ "status": "completed",
43334333 "created_at": "2025-12-28T21:46:45.822343200-05:00",
43344334- "updated_at": "2025-12-28T21:46:45.822343200-05:00",
43344334+ "updated_at": "2025-12-28T22:51:46.665792900-05:00",
43354335 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}"
43364336 },
43374337 {
···43404340 "node_type": "action",
43414341 "title": "Updated extension checkSession to read cookie via browser.cookies API and pass as query parameter. Workaround for Firefox SameSite=Lax cookie partitioning.",
43424342 "description": null,
43434343- "status": "pending",
43434343+ "status": "completed",
43444344 "created_at": "2025-12-28T21:52:22.059862700-05:00",
43454345- "updated_at": "2025-12-28T21:52:22.059862700-05:00",
43454345+ "updated_at": "2025-12-28T22:51:46.765539200-05:00",
43464346 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}"
43474347 },
43484348 {
···43514351 "node_type": "outcome",
43524352 "title": "Extension now uses browser.cookies.get() API to read session cookie and pass as query parameter. Workaround for Firefox SameSite=Lax cookie partitioning in extensions. Extension rebuilt successfully.",
43534353 "description": null,
43544354- "status": "pending",
43544354+ "status": "completed",
43554355 "created_at": "2025-12-28T22:51:31.578965200-05:00",
43564356- "updated_at": "2025-12-28T22:51:31.578965200-05:00",
43564356+ "updated_at": "2025-12-28T22:51:46.868827600-05:00",
43574357 "metadata_json": "{\"branch\":\"master\",\"confidence\":95}"
43584358 }
43594359 ],