You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-`https://github-tracker.<account>.workers.dev/oauth/callback` (preview — GitHub's subdomain matching should allow per-branch preview aliases like `alias.github-tracker.<account>.workers.dev` to work; verify after first preview deploy)
|**Members**| Read-only |`GET /user/orgs` — list user's organizations for the org selector |
64
-
65
-
**Account permissions:**
66
-
67
-
| Permission | Access | Used for |
68
-
|------------|--------|----------|
69
-
|_(none required)_|||
70
-
71
-
7. Under **Where can this GitHub App be installed?**:
72
-
-**Any account** — the app uses OAuth authorization (not installation tokens), so any GitHub user needs to be able to authorize via the login flow
73
-
8. Click **Create GitHub App**
74
-
9. Note the **Client ID** — this is your `VITE_GITHUB_CLIENT_ID`
75
-
10. Click **Generate a new client secret** and save it for the Worker secrets below
76
-
77
-
### Notifications API limitation
78
-
79
-
The GitHub Notifications API (`GET /notifications`) does not support GitHub App user access tokens — only classic personal access tokens. The app uses notifications as a polling optimization gate (skip full fetch when nothing changed). When the notifications endpoint returns 403, the gate **auto-disables** and the app falls back to time-based polling. No functionality is lost; polling is just slightly less efficient.
**Note:** The `repo` scope grants write access to repositories, but this app never performs write operations (POST/PUT/PATCH/DELETE on repo endpoints). It is read-only by design.
- Set its Client ID and Secret in `.dev.vars` (see Local Development below)
80
55
81
56
## Cloudflare Worker Secrets
82
57
@@ -91,41 +66,30 @@ wrangler secret put ALLOWED_ORIGIN
91
66
```
92
67
93
68
-`GITHUB_CLIENT_ID`: same value as `VITE_GITHUB_CLIENT_ID`
94
-
-`GITHUB_CLIENT_SECRET`: the Client Secret from your GitHub App
69
+
-`GITHUB_CLIENT_SECRET`: the Client Secret from your GitHub OAuth App
95
70
-`ALLOWED_ORIGIN`: `https://gh.gordoncode.dev`
96
71
97
-
### Preview versions
98
-
99
-
Preview deployments use `wrangler versions upload` (not a separate environment), so they inherit production secrets automatically. No additional secret configuration is needed.
100
-
101
-
CORS note: Preview URLs are same-origin (SPA and API share the same `*.workers.dev` host), so the `ALLOWED_ORIGIN` strict-equality check is irrelevant — browsers don't enforce CORS on same-origin requests.
102
-
103
-
**Migration note:** If you previously deployed with `wrangler deploy --env preview`, an orphaned `github-tracker-preview` worker may still exist. Delete it via `wrangler delete --name github-tracker-preview` or through the Cloudflare dashboard.
104
-
105
72
## Worker API Endpoints
106
73
107
-
| Endpoint | Method | Auth | Purpose |
108
-
|----------|--------|------|---------|
109
-
|`/api/oauth/token`| POST | none | Exchange OAuth code for access token. Refresh token set as HttpOnly cookie. |
|`/api/oauth/logout`| POST | none | Clears the `github_tracker_rt` HttpOnly cookie (`Max-Age=0`). |
112
-
|`/api/health`| GET | none | Health check. Returns `OK`. |
74
+
| Endpoint | Method | Purpose |
75
+
|----------|--------|---------|
76
+
|`/api/oauth/token`| POST | Exchange OAuth authorization code for permanent access token. |
77
+
|`/api/health`| GET | Health check. Returns `OK`. |
113
78
114
-
### Refresh Token Security
79
+
### Token Storage Security
115
80
116
-
The refresh token (6-month lifetime) is stored as an **HttpOnly cookie** — never in `localStorage`or the response body. This protects the high-value long-lived credential from XSS:
81
+
The OAuth App access token is a permanent credential (no expiry). It is stored in `localStorage`under the key `github-tracker:auth-token`:
117
82
118
-
-Production cookie: `__Host-github_tracker_rt` with `HttpOnly; Secure; SameSite=Strict; Path=/`
119
-
-Local dev: `github_tracker_rt` with `HttpOnly; SameSite=Lax; Path=/` (no `Secure` — localhost is HTTP; no `__Host-` prefix — requires `Secure`)
120
-
-The short-lived access token (8hr) is held in-memory only (never persisted to `localStorage`); on page reload, `refreshAccessToken()` obtains a fresh token via the cookie
121
-
- On logout, the client calls `POST /api/oauth/logout` to clear the cookie
122
-
-GitHub rotates the refresh token on each use; the Worker sets the new value as a cookie
83
+
-**CSP protects against XSS token theft**: `script-src 'self'` prevents injection of unauthorized scripts that could read `localStorage`
84
+
-On page load, `validateToken()` calls `GET /user` to verify the token is still valid
85
+
-On 401, the app immediately clears auth and redirects to login (token is revoked, not expired)
86
+
- On logout, the token is removed from `localStorage` and all local state is cleared
87
+
-Transient network errors do NOT clear the token (permanent tokens survive connectivity issues)
123
88
124
89
### CORS
125
90
126
91
-`Access-Control-Allow-Origin`: exact match against `ALLOWED_ORIGIN` (no wildcards)
127
-
-`Access-Control-Allow-Credentials: true`: enables cookie-based refresh for cross-origin preview deploys
128
-
- Same-origin requests (production, local dev) send cookies automatically without CORS
92
+
- No `Access-Control-Allow-Credentials` header (OAuth App uses no cookies)
129
93
130
94
## Local Development
131
95
@@ -138,9 +102,15 @@ pnpm run build
138
102
wrangler deploy
139
103
```
140
104
141
-
For preview (uploads a version without promoting to production):
If you previously deployed with the GitHub App model (HttpOnly cookie refresh tokens), follow these steps:
108
+
109
+
1.**Update GitHub Actions variable**: change `VITE_GITHUB_CLIENT_ID` to your OAuth App's Client ID
110
+
2.**Update Cloudflare secrets**: re-run `wrangler secret put GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` with OAuth App values
111
+
3.**Update `ALLOWED_ORIGIN`** if it changed (usually unchanged)
112
+
4.**Redeploy** the Worker: `pnpm run build && wrangler deploy`
113
+
5.**Existing users** will be logged out on next page load (their refresh cookie is no longer valid; they will be prompted to log in again via the new OAuth App flow)
114
+
6.**Delete the old GitHub App** (optional): GitHub → Settings → Developer settings → GitHub Apps → your app → Advanced → Delete
115
+
116
+
The old `POST /api/oauth/refresh` and `POST /api/oauth/logout` endpoints no longer exist and return 404.
0 commit comments