GitHub auth
Configure GitHub OAuth (signup + connect) and optional GitHub allowlists for a self-hosted server.
This guide covers GitHub auth on the Happier server:
- GitHub OAuth (signup + connect)
- Enforcing GitHub as a required login provider
- Optional allowlists (users/orgs) and offboarding behavior
Quick start: GitHub signup (recommended for public servers)
Use this when you want users to sign up with GitHub and you want to disable anonymous signup.
Note: Happier accounts are still device-key accounts. GitHub acts as an attached identity provider (used for signup, connect, and policy enforcement), not as a replacement for device-key login.
UI note:
- If both anonymous signup and GitHub signup are enabled, the welcome screen shows Create account and Continue with GitHub.
- If anonymous signup is disabled, the welcome screen shows Continue with GitHub (and no anonymous “Create account” option).
1) Create a GitHub OAuth App
Happier uses a GitHub OAuth App (not a GitHub App) for the OAuth redirect flow.
- In GitHub, go to Settings → Developer settings → OAuth Apps → New OAuth App.
- Set Authorization callback URL to:
https://YOUR_SERVER/v1/oauth/github/callback
- Create the app and copy:
- Client ID
- Client secret
Notes:
- The Happier server currently talks to
github.com/api.github.comdirectly, so this setup is for GitHub.com (not GitHub Enterprise Server). - The callback URL must match exactly (scheme/host/path) what you put in
GITHUB_REDIRECT_URL. - GitHub generally requires
https://callback URLs, except for loopback development URLs likehttp://localhost:PORT/.... - You do not need GitHub’s “Device Flow / device authentication flow”. Our server uses the standard browser redirect OAuth flow, so you can leave “Enable Device Flow” disabled.
2) Configure the server
Set these environment variables on apps/server (see apps/server/.env.example):
# GitHub OAuth (OAuth App)
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
GITHUB_REDIRECT_URL=https://YOUR_SERVER/v1/oauth/github/callback
# OAuth return redirect back to the client (required unless you are using https://app.happier.dev)
# - Web: set this to the URL you open in the browser for the Happier web app (self-hosted or local dev).
# - Mobile: use HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE + HAPPIER_OAUTH_RETURN_ALLOWED_SCHEMES instead.
HAPPIER_WEBAPP_URL=https://YOUR_WEBAPP
# Auth policy
AUTH_ANONYMOUS_SIGNUP_ENABLED=false
AUTH_SIGNUP_PROVIDERS=github
AUTH_REQUIRED_LOGIN_PROVIDERS=githubAlternative (mobile deep link return):
HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE=myapp://oauthHAPPIER_OAUTH_RETURN_ALLOWED_SCHEMES=myapp
3) Validate it works
- Restart the server.
- Check
GET /v1/featuresand confirm:capabilities.oauth.providers.github.configuredistrue
- Open the Happier app and confirm “Continue with GitHub” is available.
- If your GitHub login is already taken (or doesn’t match the username rules), Happier will ask you to choose a username during signup. This is expected.
- Important: this is signup (creating a new Happier account). If you’re trying to use GitHub to “log in” to an existing Happier account from another device, you must use device-key restore (“Login with mobile app”) and then connect GitHub from Settings → Account.
Troubleshooting:
- If you see an error like “provider already linked”, it means this GitHub identity is already connected to an existing Happier account on that server.
- Use device-key restore on this device/browser, then continue.
Server env (GitHub OAuth)
Required:
GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETGITHUB_REDIRECT_URL(preferred) or legacyGITHUB_REDIRECT_URI- Must be:
https://YOUR_SERVER/v1/oauth/github/callback
- Must be:
Required unless you are using the hosted client at https://app.happier.dev:
HAPPIER_WEBAPP_URL(defaulthttps://app.happier.dev)
Optional (typically only needed for mobile deep links / custom schemes):
HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASEHAPPIER_OAUTH_RETURN_ALLOWED_SCHEMESOAUTH_STATE_TTL_SECONDS(default600, clamp 60–3600)OAUTH_PENDING_TTL_SECONDS(default600, clamp 60–3600; legacy fallback:GITHUB_OAUTH_PENDING_TTL_SECONDS)GITHUB_HTTP_TIMEOUT_SECONDS(default10, clamp 1–120)
Notes:
GITHUB_REDIRECT_URLmust be reachable by GitHub (it’s where GitHub redirects the browser after the user approves OAuth).- If your server is behind a reverse proxy,
GITHUB_REDIRECT_URLshould be the public URL (not an internal container hostname). HAPPIER_WEBAPP_URL/HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASEare only “optional” if you are using the hosted client athttps://app.happier.dev.- If you are self-hosting the web app, or using a local dev web UI, you must set one of these so the server can redirect back to your client after OAuth.
OAuth return URL to the client (advanced)
After the server handles the GitHub callback, it redirects the browser back to the client so the client can finish the flow.
- Default return base:
HAPPIER_WEBAPP_URL(https://app.happier.dev)- The server redirects to
${HAPPIER_WEBAPP_URL}/oauth/github?...unless you override it.
- The server redirects to
- Override return base (without provider suffix):
HAPPIER_WEBAPP_OAUTH_RETURN_URL_BASE- Example:
https://app.example.com/custom-oauth→ redirects tohttps://app.example.com/custom-oauth/github?...
- Example:
- Allow additional URL schemes for the return redirect:
HAPPIER_OAUTH_RETURN_ALLOWED_SCHEMES- Use this for mobile deep links (e.g.
myapp) http://is only allowed for loopback hosts likelocalhost,127.0.0.1, and*.localhost, and is not allowed for non-loopback hosts.
- Use this for mobile deep links (e.g.
Troubleshooting:
- If you get redirected to
https://app.happier.deveven after settingHAPPIER_WEBAPP_URL, the server likely rejected your configured return URL as unsafe. For local web dev, usehttp://localhost:PORTorhttp://*.localhost:PORT(or usehttps://).
OAuth scopes
OAuth scopes requested by the server:
- Default:
read:user - Adds
read:orgonly when you enable org allowlists and setAUTH_GITHUB_ORG_MEMBERSHIP_SOURCE=oauth_user_token
GitHub allowlists (eligibility)
Important:
- All values are normalized to lowercase.
- Allowlists affect access only when GitHub is included in
AUTH_REQUIRED_LOGIN_PROVIDERS.
User allowlist
AUTH_GITHUB_ALLOWED_USERS(CSV of GitHub logins)
If set and GitHub is required for login, the user must match this list or they get 403 not-eligible.
Org allowlist
AUTH_GITHUB_ALLOWED_ORGS(CSV of org slugs)AUTH_GITHUB_ORG_MATCH(any/all, defaultany)
If set and GitHub is required for login, the user must be in the allowed org(s). Membership is re-checked using the offboarding interval.
Org membership source (important)
AUTH_GITHUB_ORG_MEMBERSHIP_SOURCE controls how the server verifies org membership:
github_app(recommended)oauth_user_token(uses the user’s OAuth token and requiresread:org)
Default behavior:
- If
AUTH_GITHUB_ALLOWED_ORGSis empty →oauth_user_token(no org checks happen) - If
AUTH_GITHUB_ALLOWED_ORGSis set → defaults togithub_app
This means: if you set AUTH_GITHUB_ALLOWED_ORGS but you do not configure GitHub App mode, users will be treated as ineligible.
GitHub App mode (recommended for org enforcement)
GitHub App mode avoids relying on user OAuth tokens and keeps org enforcement working even if a user revokes OAuth consent.
Server environment variables (GitHub App mode)
AUTH_GITHUB_APP_IDAUTH_GITHUB_APP_PRIVATE_KEY(PEM)AUTH_GITHUB_APP_INSTALLATION_ID_BY_ORG(CSV mapping likeacme=123,other=456)
GitHub setup steps (GitHub App)
- Create a GitHub App: Settings → Developer settings → GitHub Apps → New GitHub App.
- Generate a private key and copy the PEM into
AUTH_GITHUB_APP_PRIVATE_KEY. - Set the minimal permission needed for membership checks:
- Organization permissions → Members: Read
- Install the app into each org you plan to allow.
- Capture the installation id for each org and set
AUTH_GITHUB_APP_INSTALLATION_ID_BY_ORG.
Installation id tips:
- After installing the app, click Configure on the installation; the URL usually contains
installations/<id>.
Org enforcement via user OAuth tokens (alternative)
If you can’t use GitHub App mode, you can verify org membership using the user’s OAuth token:
AUTH_GITHUB_ALLOWED_ORGS=acme
AUTH_GITHUB_ORG_MEMBERSHIP_SOURCE=oauth_user_token
GITHUB_STORE_ACCESS_TOKEN=trueNotes:
- Users will be prompted for
read:orgduring OAuth. - Token storage is required for periodic org re-checks; if you disable token storage, org checks will fail and users can become ineligible.
- If you switch to this mode after users already connected GitHub, they may need to disconnect/reconnect so the server can store a token for membership checks.
Token storage (advanced)
GITHUB_STORE_ACCESS_TOKEN controls whether the server persists GitHub access tokens (encrypted-at-rest).
- Default:
falsefor typical setups (Friends / basic GitHub connect) - Default: effectively
truewhen you enable org checks viaoauth_user_token(token required for offboarding)
Example configurations
GitHub-only signup + GitHub required for login
AUTH_ANONYMOUS_SIGNUP_ENABLED=false
AUTH_SIGNUP_PROVIDERS=github
AUTH_REQUIRED_LOGIN_PROVIDERS=githubHybrid (anonymous + GitHub signup)
This is useful for private servers (VPN / Tailscale / LAN), where you want to keep anonymous accounts available but also offer “Continue with GitHub”.
AUTH_ANONYMOUS_SIGNUP_ENABLED=true
AUTH_SIGNUP_PROVIDERS=github
AUTH_REQUIRED_LOGIN_PROVIDERS=GitHub-only + restrict to an org (GitHub App mode)
AUTH_ANONYMOUS_SIGNUP_ENABLED=false
AUTH_SIGNUP_PROVIDERS=github
AUTH_REQUIRED_LOGIN_PROVIDERS=github
AUTH_GITHUB_ALLOWED_ORGS=acme
AUTH_GITHUB_ORG_MEMBERSHIP_SOURCE=github_app
AUTH_GITHUB_APP_ID=...
AUTH_GITHUB_APP_PRIVATE_KEY=...
AUTH_GITHUB_APP_INSTALLATION_ID_BY_ORG=acme=123