Environment variables
The repository’s .env.example file is the canonical configuration reference.
Required Community settings
Section titled “Required Community settings”| Variable | Required | Description |
|---|---|---|
DATABASE_URL | Outside demo mode | PostgreSQL connection string. |
BETTER_AUTH_SECRET | Outside demo mode | Random secret used by Better Auth. Generate at least 32 bytes. |
APP_URL | Yes for email links | Public application origin, including http:// or https://. |
BETTER_AUTH_URL | Deployed auth | Origin Better Auth uses for auth links and OAuth callbacks. |
Google and GitHub sign-in
Section titled “Google and GitHub sign-in”Google and GitHub are optional. Configure both values for a provider to enable its sign-in, sign-up, and connect buttons. Unconfigured providers are hidden. When none are configured, the auth forms show only email and password, without a social divider. Existing connections remain manageable in Settings → Security even after a provider is disabled.
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID | Google OAuth Web application client ID. |
GOOGLE_CLIENT_SECRET | Google OAuth client secret. |
GITHUB_CLIENT_ID | GitHub OAuth App client ID. |
GITHUB_CLIENT_SECRET | GitHub OAuth client secret. |
Keep these values in the server environment. Never prefix a client secret with VITE_ or commit it. Restart the application after changing credentials. A provider with only one value configured causes a startup error.
Configure Google
Section titled “Configure Google”- Open Google Auth Platform in your Google Cloud project.
- Configure the app name, support email, homepage, privacy-policy URL, and authorized domain under Branding. Select an External audience for public customer access.
- Under Clients, create a Web application OAuth client. Register the exact redirect URI
<APP_URL>/api/auth/callback/google. Leave Authorized JavaScript origins empty for the current server redirect flow. Leave the AI-powered agent option unchecked. - Store the client ID and secret as
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETon the server. SetAPP_URL,BETTER_AUTH_URL, and anySPARKFEED_APP_ORIGINoverride to the same application origin. - Test with an allowed account. Set the audience to production for public access and complete any requested branding verification.
Google sign-in requests only openid, email, and profile. It does not request Gmail or Drive access. Use separate OAuth clients for isolated testing. Multiple clients can share one Google Cloud project and its consent-screen branding.
Enable Google on Railway
Section titled “Enable Google on Railway”For Sparkfeed’s hosted release, deploy dev to SparkFeed-Application at beta.sparkfeed.dev first. Leave both Google variables unset on beta. Verify email sign-in, the absence of unconfigured social buttons and their divider before merging dev into main. SparkFeed-Production at app.sparkfeed.dev tracks main. Both services are currently inside the Railway environment named production, so check the service name and domain when editing variables.
- Select the production Railway environment and the customer application service whose custom domain is
app.sparkfeed.dev. - Confirm that the deployment source includes the Google provider, provider discovery, and connected-account UI. Adding variables does not upload local code changes.
- Open Variables and add
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETas service variables. Enter both values directly in Railway. Do not paste them into chat, issue trackers, or committed files. - Save a recovery copy of the secret in your password manager. Use the secret variable’s three-dot menu to select Seal. Railway provides sealed values to builds and deployments but does not reveal them in its UI or API. A sealed variable cannot be unsealed.
- Set these non-secret variables for production:
APP_URL=https://app.sparkfeed.devBETTER_AUTH_URL=https://app.sparkfeed.devSPARKFEED_APP_ORIGIN=https://app.sparkfeed.devSPARKFEED_ENVIRONMENT=productionVITE_DEMO_MODE=false- Leave
VITE_AUTH_URLunset for the normal same-origin deployment. If an existing deployment sets it, confirm that it equalshttps://app.sparkfeed.dev. - Keep the deployment’s existing
BETTER_AUTH_SECRETandDATABASE_URL. The auth secret also encrypts stored OAuth tokens. Do not rotate it while adding Google credentials. - Review Railway’s staged changes for the selected service. Deploy the intended code and variable changes together. Railway does not apply staged variables to the running deployment until deployment.
- Wait for a successful deployment and the
/api/healthcheck. The repository’s Railway start command runs database migrations before starting the server. Check migration and startup logs if deployment fails. - Open
https://app.sparkfeed.dev/sign-inin a private browser window. Confirm that Google appears. GitHub appears only when both GitHub variables are configured. Complete the checks below.
The production Google client must contain https://app.sparkfeed.dev/api/auth/callback/google as an authorized redirect URI. The landing-page domain is not a JavaScript origin for this flow. Keep production credentials out of beta, local development, the documentation service, and the private staff dashboard.
Hosted beta disables Google whenever SPARKFEED_ENVIRONMENT=beta, even if Google credentials are present. Leave its Google variables unset. For a separate development instance that needs Google testing, use an isolated OAuth client. Sealed Railway variables are not copied when duplicating an environment or service.
See Railway service and sealed variables and Railway staged deployments.
Configure GitHub
Section titled “Configure GitHub”- In GitHub Developer settings, register an OAuth App. For hosted production, use the name
Sparkfeed-BetterAuth-Prod, homepagehttps://sparkfeed.dev, and exact redirect URIhttps://app.sparkfeed.dev/api/auth/callback/github. - Leave wildcard matching and Device Flow disabled. Token expiry can stay enabled; Better Auth supports GitHub refresh tokens when issued.
- Generate a client secret. Add
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETto SparkFeed-Production in Railway and deploy the staged variables. Keep both unset on beta. Seal the secret after saving a recovery copy in a password manager. - Test sign-in with a GitHub account whose primary email is private, then connect and disconnect GitHub under Settings → Security. Better Auth requests
read:useranduser:emailby default to retrieve a verified email.
This setup uses a GitHub OAuth App. If you instead create a GitHub App, grant Account permissions → Email addresses → Read-only. Never request repository access just for sign-in. See Better Auth’s GitHub provider.
Review authentication in the staff dashboard
Section titled “Review authentication in the staff dashboard”Open a user detail page in the private dashboard. Sign-in methods & connected accounts shows the current provider connections and when they were added. Authentication history shows the latest 50 successful sign-ins and connection changes. Sessions & devices shows the method recorded when each session was created.
History starts when this version is deployed; earlier sessions show Not recorded. Session refreshes are not new sign-ins. Failed attempts are not included. Customer deletion removes the associated history. The signed staff API returns an explicit projection with no passwords, OAuth tokens, or session tokens. This history is enabled only for the cloud edition.
Diagnose a failed Google sign-in
Section titled “Diagnose a failed Google sign-in”- Google button absent: confirm that both Google variables exist on the running customer service and that its deployed code includes provider discovery. Demo mode hides Google.
redirect_uri_mismatch: compare Google’s registered URI with the callback generated from the app origin. Scheme, host, port, and path must match.SPARKFEED_APP_ORIGINtakes precedence overAPP_URLandBETTER_AUTH_URL.- Invalid client: check that the client ID and secret belong to the same Google Web application client. Update the secret directly in Railway and redeploy.
- Registration refused: check the instance’s registration policy. Google signup uses the same restrictions as email signup. Do not open registration solely to bypass a test failure.
- Account not linked: verify the existing Sparkfeed email, sign in with the existing method, and connect Google under Settings → Security.
To disable Google during incident recovery, remove both Google variables in one staged deployment. Removing only one causes startup validation to fail. Keep email sign-in available for existing password users. Users whose only method is Google need a verified recovery method before Google is disabled. Rolling back application code does not revoke access already granted in Google or remove linked accounts.
Check sign-in and account linking
Section titled “Check sign-in and account linking”- A new provider identity creates a Sparkfeed user through the existing registration and workspace hooks. Instance registration restrictions still apply.
- A provider-verified email matching an existing, verified Sparkfeed email links to that same user. Existing workspaces and data remain attached to the original user ID.
- An unverified existing Sparkfeed email must be verified first. If automatic linking is refused, sign in with the existing method and connect the provider under Settings → Security.
- A signed-in user can explicitly connect a provider with a different verified email. The connection does not change the Sparkfeed email or profile. It does not merge two existing Sparkfeed accounts.
- A provider identity already linked to another Sparkfeed user cannot be moved through the connect button.
- Disconnecting the last sign-in method is blocked. Social-only users can add an email password through the password reset flow.
Test a new signup, a returning signup with a matching email, an explicit connection, and a disconnect before releasing. Confirm that the browser returns to Sparkfeed, that the original user’s data is still present, and that the last method cannot be disconnected.
See the Better Auth account-linking documentation and Google branding-verification guidance.
Registration and workspaces
Section titled “Registration and workspaces”| Variable | Default | Description |
|---|---|---|
ALLOW_REGISTRATION | false | Allows public signup after the first account when set to true. A valid invitation still works when false. |
WORKSPACE_CREATION_POLICY | owner-only | Use all-users to let every registered account create workspaces. |
The first account can register even when ALLOW_REGISTRATION=false. That account becomes the instance owner.
AI providers
Section titled “AI providers”Set at least one provider key to enable Spark AI:
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
AI_GATEWAY_API_KEY | Vercel AI Gateway |
OPENROUTER_API_KEY | OpenRouter |
AI_DEFAULT_MODEL can select a model ID from src/config/ai-models.json. DISABLE_AI=true disables Spark AI for the whole instance.
Use Resend or SMTP. Set EMAIL_FROM for either route.
| Variable | Description |
|---|---|
RESEND_API_KEY | Resend credential. |
SMTP_HOST, SMTP_PORT | SMTP server. |
SMTP_USER, SMTP_PASS | SMTP credentials. |
SMTP_SECURE, SMTP_IGNORE_TLS | SMTP transport controls. |
Without an email provider, verification, invitation, and password-reset messages cannot reach users.
Demo mode
Section titled “Demo mode”Set VITE_DEMO_MODE before building and keep the same value at runtime:
VITE_DEMO_MODE=trueDemo mode ignores DATABASE_URL, uses rss-demo.db, bypasses auth, seeds sample content, and blocks mutations.