Repository navigation
OAuth setup guide (app owner)
This guide is for the owner of the Endowment app who creates and manages sign-in with X, Discord, Google (and Microsoft when enabled). You will register callback URLs in each provider’s developer portal, then copy Client ID and Client Secret into the app’s production configuration.
Live app: https://endowment.zeroauthoritydao.com
Sign-in providers wired today: X, Discord, Google
Shown in UI but not wired yet: Microsoft, GitHub, LinkedIn
For each provider you will set three things in their portal (not in this repo):
| Item | Where you set it | What you copy out |
|---|---|---|
| Callback / redirect URI | Provider developer console | Nothing to copy — use the exact URLs in the table below |
| Client ID | Same console | Give to whoever deploys the app (see Hand off to production) |
| Client secret | Same console | Same — treat like a password; shown once on some portals |
All flows use OAuth 2.0 with PKCE. Do not change scopes unless engineering asks you to.
Register these in each provider console for the live site. Use the full URL exactly — correct https, host, path, no trailing slash.
App base URL (production): https://endowment.zeroauthoritydao.com
Callback path pattern: {base URL}/api/auth/oauth/{provider}/callback
| Provider | Production callback URL (register this) |
|---|---|
| X | https://endowment.zeroauthoritydao.com/api/auth/oauth/x/callback |
| Discord | https://endowment.zeroauthoritydao.com/api/auth/oauth/discord/callback |
https://endowment.zeroauthoritydao.com/api/auth/oauth/google/callback |
|
| Microsoft (when enabled) | https://endowment.zeroauthoritydao.com/api/auth/oauth/microsoft/callback |
Google only — also add authorized JavaScript origin: https://endowment.zeroauthoritydao.com
Website / app URL fields in provider consoles should use https://endowment.zeroauthoritydao.com where asked.
Updating DNS or the site URL is not enough for login to keep working:
- Register the new production callback URLs (and Google origin) in every provider console.
- Give the deployer the updated production base URL and credentials if apps were recreated.
- Test sign-in on the new domain before removing old callback URLs.
- Update this document with the new hostname so future setup stays correct.
Until provider consoles match the live URL, users will see errors such as redirect_uri_mismatch.
After you create each OAuth app, send these to whoever manages production hosting (Vercel, Railway, etc.). They enter them as environment variables — not in git.
| Variable | Value |
|---|---|
APP_BASE_URL |
https://endowment.zeroauthoritydao.com |
AUTH_SECRET |
Long random secret (32+ characters); unique to production |
X_CLIENT_ID |
From X developer portal |
X_CLIENT_SECRET |
From X developer portal |
DISCORD_CLIENT_ID |
From Discord developer portal |
DISCORD_CLIENT_SECRET |
From Discord developer portal |
GOOGLE_CLIENT_ID |
From Google Cloud Console |
GOOGLE_CLIENT_SECRET |
From Google Cloud Console |
Optional overrides (only if a portal was configured with a non-standard callback): X_REDIRECT_URI, DISCORD_REDIRECT_URI, GOOGLE_REDIRECT_URI — each must match the portal character for character.
Production checklist
- Every provider has the production callback URL from the table above.
- Client ID and secret for X, Discord, and Google are in hosting secrets.
-
APP_BASE_URLishttps://endowment.zeroauthoritydao.com(no trailing slash). - Google OAuth consent screen is In production when all users should sign in (not only test users).
- Sign-in tested on endowment.zeroauthoritydao.com for X, Discord, and Google.
| Provider | Scopes |
|---|---|
| X |
users.read, tweet.read, offline.access
|
| Discord |
identify, email
|
openid, email, profile
|
Portal: X Developer Portal → your Project → App → User authentication settings
- Enable OAuth 2.0 (not OAuth 1.0a-only).
- Type of app: Web App (typical for this site).
-
Callback URI / Redirect URL: add
https://endowment.zeroauthoritydao.com/api/auth/oauth/x/callback -
Website URL:
https://endowment.zeroauthoritydao.com - Ensure permissions allow user read (
users.readat minimum). - Save and copy Client ID and Client Secret (secret may only appear once).
Verify: On the live site, open Log in → X → complete consent → return signed in.
Portal: Discord Developer Portal → your application → OAuth2
- OAuth2 → General: copy Client ID; reveal/copy Client Secret.
-
OAuth2 → Redirects → Add Redirect:
https://endowment.zeroauthoritydao.com/api/auth/oauth/discord/callback - Scopes used by the app:
identify,email. - Optional: set app icon and description so users recognize the consent screen.
Verify: Log in → Discord on the live site.
Portal: Google Cloud Console → your project → APIs & Services
-
OAuth consent screen
- Configure app name, support email, and developer contact.
- Scopes:
openid,email,profile. - For public launch: set publishing status to In production (Testing mode only allows listed test users).
-
Credentials → Create credentials → OAuth client ID
- Application type: Web application
-
Authorized JavaScript origins:
https://endowment.zeroauthoritydao.com -
Authorized redirect URIs:
https://endowment.zeroauthoritydao.com/api/auth/oauth/google/callback
- Copy Client ID and Client secret.
Do not use Desktop or Android client types for this website flow.
Verify: Log in → Google on the live site.
Microsoft appears in the login UI but engineering has not enabled it. When you are asked to set it up, use the same production callback pattern.
Portal: Microsoft Entra admin center → App registrations → New registration
| Field | Value |
|---|---|
| Name | Endowment (or your product name) |
| Supported account types | Personal + work/school accounts (if you want both) |
| Redirect URI (Web) | https://endowment.zeroauthoritydao.com/api/auth/oauth/microsoft/callback |
Then: copy Application (client) ID; create a client secret under Certificates & secrets; add Graph delegated permissions openid, email, profile, User.Read as directed by engineering.
| Symptom | Likely cause | What to check |
|---|---|---|
redirect_uri_mismatch |
Callback in portal ≠ live URL | Production callback table above; no typo or trailing slash |
invalid_client |
Wrong or rotated secret | Re-copy Client ID and secret into hosting env |
| Google “Access blocked” | App still in Testing | Publish consent screen or add user as test user |
| Discord “Invalid OAuth2 redirect_uri” | Redirect not added | OAuth2 → Redirects in Discord portal |
| X login fails | OAuth 2.0 off or wrong callbacks | User authentication settings and callback list |
This section is not for production setup. It explains optional dev settings when someone runs the app on their own machine (
pnpm dev). The app owner normally only needs the production sections above.
| Item | Dev value |
|---|---|
| Base URL | http://localhost:3000 |
| X callback | http://localhost:3000/api/auth/oauth/x/callback |
| Discord callback | http://localhost:3000/api/auth/oauth/discord/callback |
| Google callback | http://localhost:3000/api/auth/oauth/google/callback |
| Google JS origin | http://localhost:3000 |
Add these in addition to production URLs in each provider portal if engineers need to test login locally.
-
.env.exampleinpackages/webis a dev template only (placeholders, safe to commit). - Engineers copy it to
.env(gitignored) on their laptop. - Production does not use
.envfrom the repo; production uses hosting secrets with the same variable names.
Dev .env example:
AUTH_SECRET="dev-only-secret-at-least-32-characters-long"
APP_BASE_URL="http://localhost:3000"
X_CLIENT_ID="..."
X_CLIENT_SECRET="..."
DISCORD_CLIENT_ID="..."
DISCORD_CLIENT_SECRET="..."
GOOGLE_CLIENT_ID="..."
GOOGLE_CLIENT_SECRET="..."Dev verify: From the repo, run pnpm dev, open http://localhost:3000, and test Log in for each provider.
| Provider | Code | Login start route | Callback path |
|---|---|---|---|
| X | x-oauth.ts |
/api/auth/x/start |
/api/auth/oauth/x/callback |
| Discord | discord-oauth.ts |
/api/auth/discord/start |
/api/auth/oauth/discord/callback |
google-oauth.ts |
/api/auth/google/start |
/api/auth/oauth/google/callback |
Env validation: packages/web/src/env.js · Dev template: packages/web/.env.example