CLOUDFLARE_API_TOKEN
- Go to Cloudflare Dashboard → My Profile → API Tokens
- Click "Create Token"
- Use the "Edit Cloudflare Workers" template
- Scope to your account and zone as needed
- Copy the token and add it as a secret
CLOUDFLARE_ACCOUNT_ID
- Go to Cloudflare Dashboard
- Select your account (Account Home)
- Copy the Account ID from the right sidebar
- Add it as a secret
VITE_GITHUB_CLIENT_ID
- This is the GitHub OAuth App Client ID (not a secret — it is embedded in the built JS bundle)
- Add it as an Actions variable (not a secret)
- See OAuth App setup below for how to obtain it
- Go to GitHub → Settings → Developer settings → OAuth Apps → New OAuth App
- Fill in the details:
- Application name: your app name (e.g.
gh-tracker-yourname) - Homepage URL:
https://gh.gordoncode.dev - Authorization callback URL:
https://gh.gordoncode.dev/oauth/callback
- Application name: your app name (e.g.
- Click Register application
- Note the Client ID — this is your
VITE_GITHUB_CLIENT_ID - Click Generate a new client secret and save it for the Worker secrets below
The login flow requests scope=repo read:org notifications:
| Scope | Used for |
|---|---|
repo |
Read issues, PRs, check runs, workflow runs (includes private repos) |
read:org |
GET /user/orgs — list user's organizations for the org selector |
notifications |
GET /notifications — polling optimization gate (304 = skip full fetch) |
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.
Create a second OAuth App for local development:
- Authorization callback URL:
http://localhost:5173/oauth/callback - Set its Client ID and Secret in
.dev.vars(see Local Development below)
These are set via wrangler CLI and are stored in the Cloudflare Worker runtime (not in GitHub).
wrangler secret put GITHUB_CLIENT_ID
wrangler secret put GITHUB_CLIENT_SECRET
wrangler secret put ALLOWED_ORIGINGITHUB_CLIENT_ID: same value asVITE_GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET: the Client Secret from your GitHub OAuth AppALLOWED_ORIGIN:https://gh.gordoncode.dev
| Endpoint | Method | Purpose |
|---|---|---|
/api/oauth/token |
POST | Exchange OAuth authorization code for permanent access token. |
/api/health |
GET | Health check. Returns OK. |
The OAuth App access token is a permanent credential (no expiry). It is stored in localStorage under the key github-tracker:auth-token:
- CSP protects against XSS token theft:
script-src 'self'prevents injection of unauthorized scripts that could readlocalStorage - On page load,
validateToken()callsGET /userto verify the token is still valid - On 401, the app immediately clears auth and redirects to login (token is revoked, not expired)
- On logout, the token is removed from
localStorageand all local state is cleared - Transient network errors do NOT clear the token (permanent tokens survive connectivity issues)
Access-Control-Allow-Origin: exact match againstALLOWED_ORIGIN(no wildcards)- No
Access-Control-Allow-Credentialsheader (OAuth App uses no cookies)
Copy .dev.vars.example to .dev.vars and fill in your values. Wrangler picks up .dev.vars automatically for local wrangler dev runs.
pnpm run build
wrangler deployIf you previously deployed with the GitHub App model (HttpOnly cookie refresh tokens), follow these steps:
- Update GitHub Actions variable: change
VITE_GITHUB_CLIENT_IDto your OAuth App's Client ID - Update Cloudflare secrets: re-run
wrangler secret put GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETwith OAuth App values - Update
ALLOWED_ORIGINif it changed (usually unchanged) - Redeploy the Worker:
pnpm run build && wrangler deploy - 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)
- Delete the old GitHub App (optional): GitHub → Settings → Developer settings → GitHub Apps → your app → Advanced → Delete
The old POST /api/oauth/refresh and POST /api/oauth/logout endpoints no longer exist and return 404.