Problem
Classroom 50 is a static single page app with no backend. Two GitHub endpoints it depends on don't support cross-origin requests from a browser, so the web app can't call them directly:
- OAuth token exchange.
POST https://github.com/login/oauth/access_token sends no Access-Control-Allow-Origin header, and GitHub OAuth Apps require the client_secret on that call even with PKCE. A browser can't make the request, and a secret can't ship in browser JavaScript.
- Repository archive downloads.
GET /repos/{owner}/{repo}/zipball on api.github.com responds with a 302 to codeload.github.com, which sends no CORS headers. The browser blocks the redirected response, so the zip can't be read in page.
Current workaround
Both calls go through a small stateless Cloudflare Worker (cloudflare_worker.js, deployed at classroom50.fifty-foundation.workers.dev). The web app's only touchpoint is web/src/github-core/workerProxy.ts; every other GitHub call goes straight to api.github.com.
| Route |
What the Worker does |
POST /web/token |
Injects the OAuth client secret matching the request's client_id, forwards to github.com/login/oauth/access_token, returns the response with CORS headers. |
POST /device/code, POST /device/token |
Forwards the device flow calls as is (no secret needed) and adds CORS headers. |
GET /repos/{owner}/{repo}/zipball[/{ref}] |
Follows the redirect to codeload.github.com server-side with the caller's own bearer token and streams the zip back with CORS headers. |
The Worker stores nothing. Requests are accepted only from allowlisted app origins, and the proxy base can be overridden with VITE_GITHUB_PROXY_BASE for self-hosting. Sign-in with a personal access token bypasses the Worker entirely, which is the documented fallback when workers.dev is blocked (wiki: The GitHub proxy).
Upstream tracking
- OAuth token exchange: github/roadmap#1153, "Single page app support for GitHub Apps". Would enable CORS on
/access_token for PKCE clients with no client secret. Status: Preview, currently labeled Paused. Note this applies to GitHub Apps only, so adopting it means moving from the current OAuth App to a GitHub App with expiring tokens and refresh handling.
- Archive downloads: octokit/rest.js#3 (open since 2018, marked blocked on GitHub) and community discussion #106849. No roadmap item exists for CORS on
codeload.github.com.
Done when
Until then, this issue is the place to record upstream status changes.
Problem
Classroom 50 is a static single page app with no backend. Two GitHub endpoints it depends on don't support cross-origin requests from a browser, so the web app can't call them directly:
POST https://github.com/login/oauth/access_tokensends noAccess-Control-Allow-Originheader, and GitHub OAuth Apps require theclient_secreton that call even with PKCE. A browser can't make the request, and a secret can't ship in browser JavaScript.GET /repos/{owner}/{repo}/zipballonapi.github.comresponds with a 302 tocodeload.github.com, which sends no CORS headers. The browser blocks the redirected response, so the zip can't be read in page.Current workaround
Both calls go through a small stateless Cloudflare Worker (
cloudflare_worker.js, deployed atclassroom50.fifty-foundation.workers.dev). The web app's only touchpoint isweb/src/github-core/workerProxy.ts; every other GitHub call goes straight toapi.github.com.POST /web/tokenclient_id, forwards togithub.com/login/oauth/access_token, returns the response with CORS headers.POST /device/code,POST /device/tokenGET /repos/{owner}/{repo}/zipball[/{ref}]codeload.github.comserver-side with the caller's own bearer token and streams the zip back with CORS headers.The Worker stores nothing. Requests are accepted only from allowlisted app origins, and the proxy base can be overridden with
VITE_GITHUB_PROXY_BASEfor self-hosting. Sign-in with a personal access token bypasses the Worker entirely, which is the documented fallback whenworkers.devis blocked (wiki: The GitHub proxy).Upstream tracking
/access_tokenfor PKCE clients with no client secret. Status: Preview, currently labeled Paused. Note this applies to GitHub Apps only, so adopting it means moving from the current OAuth App to a GitHub App with expiring tokens and refresh handling.codeload.github.com.Done when
/web/token,/device/code, and/device/tokenroutes from the Worker.codeload.github.com(or an equivalent browser-readable archive endpoint) and the archive route is removed.Until then, this issue is the place to record upstream status changes.