Lightweight Express starter that demonstrates a middleware-based GitHub OAuth flow and GitHub App installation/token handling. Useful as a backend for browser integrations or server-to-server plugins (e.g., WordPress plugin).
- Install dependencies:
npm install- Create a
.envfile in project root with the values below (example):
PORT=3000
NODE_ENV=development
SESSION_SECRET=replace_with_a_long_random_secret
GITHUB_CLIENT_ID=your_github_oauth_app_client_id
GITHUB_CLIENT_SECRET=your_github_oauth_app_client_secret- Start the app:
npm start
# or
node src/server.jsThe server will start on http://localhost:3000 (or the PORT you set).
PORT- (optional) HTTP port. Default:3000.NODE_ENV-development|production. Affects cookiesecurebehavior.SESSION_SECRET- secret used byexpress-sessionto sign session cookies.GITHUB_CLIENT_ID- OAuth App Client ID from GitHub.GITHUB_CLIENT_SECRET- OAuth App Client Secret from GitHub.
Optional runtime behavior:
- The session cookie
domainis set to.railway.apponly in production by the current config. Change insrc/server.jsif deploying elsewhere.
These are the main endpoints exposed by the server. All /api endpoints expect
an Authorization: Bearer <access_token> header unless noted otherwise.
- GET
/api/github/user— Get authenticated GitHub user and their orgs - GET
/api/github/installations— List GitHub App installations for the user - GET
/api/github/installations/repositories— Get all accessible repositories across installations - GET
/api/github/installations/:installation_id/repositories— Repos for a specific installation - GET
/api/github/repos/:owner/:type— (DEPRECATED) repos by owner (user/org) - GET
/api/github/repos/:owner/:repo— Repo details - GET
/api/github/repos/:owner/:repo/branches— Repo branches - POST
/api/github/cache/clear— Clear in-memory installation token cache
Auth (browser flow):
- GET
/auth/github— Redirect to GitHub for login (requiresreturn_urlquery param) - GET
/auth/github/callback— OAuth callback (GitHub redirects here) - POST
/auth/github/refresh— Exchange refresh token for a new access token - GET
/auth/logout— Destroy session and redirect to/
- Client requests
/auth/github?return_url=<where_to_return>. - Server stores the return URL in session and redirects to GitHub's authorize URL.
- After user authorizes, GitHub calls
/auth/github/callback?code=...&state=.... - Server exchanges
codefor an access token and redirects the user back to the originalreturn_url(either setting a cookie for internal pages or appending tokens to thereturn_urlfor external integrations).
Security notes:
- Cookies are set
httpOnlyand onlysecurewhenNODE_ENV=production. - For production consider storing session and token cache in a shared store (Redis).
Replace the placeholders below with your contact details.
- Author: JESUS UZCATEGUI
- Email: UZCATEGUIJESUSDEV@GMAIL.COM / INFO@JUZTSTACK.DEV
- Website: https://www.juztstack.dev
- Token cache for GitHub App installation tokens is an in-memory
Mapinsrc/services/githubAppService.js. For horizontal scaling use Redis or similar. - Logging is minimal and intended for development. Integrate a structured logger (winston/pino) for production.
Below are short deployment notes for two popular hosting providers (Railway
and Render). These instructions focus on the environment and runtime settings
you will likely need. They assume your repository is connected to the hosting
provider (GitHub link) and that your app uses process.env.PORT (already in
this template).
- Create a new project in Railway and connect the GitHub repository.
- In the Railway dashboard, add the required environment variables (
SESSION_SECRET,GITHUB_CLIENT_ID,GITHUB_CLIENT_SECRET, and any others likeREDIS_URL). - Set the start command to
npm startornode src/server.js(Railway providesPORTautomatically). - For session persistence and scaling, add the Redis plugin (Addons -> Redis)
and set
REDIS_URLin Railway. Update your app to useconnect-redisforexpress-sessionif you want sessions shared across instances. - Add a health check to Railway pointing to
/health(see suggested snippet below) so Railway can monitor the instance.
Railway example environment variables:
PORT= (provided by Railway)
NODE_ENV=production
SESSION_SECRET=replace_with_a_secret
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
REDIS_URL=redis://:password@hostname:port
- Create a new Web Service in Render and connect your repository.
- Set the build command to
npm install(ornpm ci) and the start command tonpm startornode src/server.js. - Add the environment variables in Render's dashboard (Environment -> Environment
Variables). Render sets a
PORTenv var automatically. - For session and cache persistence use a managed Redis instance and set
REDIS_URL. - Render offers Cron Jobs and Background Workers — use those for periodic token refresh tasks or long-running background work.
Render example environment variables (same as Railway):
NODE_ENV=production
SESSION_SECRET=replace_with_a_secret
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
REDIS_URL=redis://:password@hostname:port
Add a lightweight health endpoint to src/server.js so platforms and uptime
monitors can verify the app is healthy. Example snippet (copy into server.js):
app.get('/health', (req, res) => {
res.json({ status: 'ok', timestamp: Date.now() });
});This endpoint should return 200 quickly and not depend on external services.
Some hosting providers (free tiers) may put your instance to sleep when idle. Below are recommended strategies to mitigate cold starts and keep sessions available for users.
- Use an external uptime monitor (UptimeRobot, Cronitor, Pingdom) to ping a
lightweight
/healthendpoint every 5–10 minutes. This can prevent free-tier sleeping in many providers. - Use provider-native schedulers: Render has Cron Jobs, Railway has recurring
jobs (or use a small worker) — schedule a periodic request to your
/healthendpoint or a lightweight internal task. - Move session/token storage to a managed Redis instance so restarts and scaled
instances share session state. Set
REDIS_URLand useconnect-redis. - Implement a background refresh worker for long-lived integrations: store
refresh_tokensecurely and periodically refresh access tokens off the request path so clients don't experience latency. - Prefer serverless functions for event-driven or rarely-used endpoints. They avoid always-on servers and can scale to zero without losing data (store state in Redis or a DB).
- If fully self-hosting, use a process manager like
pm2or systemd to keep the app running and restart on failure.
Security note: keep-alive pings should not expose sensitive endpoints or
contain credentials. Ping only a public /health endpoint.
- Fork the repository
- Create a feature branch
- Open a pull request with a clear description of changes
This project is licensed under the MIT License — see the LICENSE file for details.