Skip to content
Live demo

Environment variables

The repository’s .env.example file is the canonical configuration reference.

VariableRequiredDescription
DATABASE_URLOutside demo modePostgreSQL connection string.
BETTER_AUTH_SECRETOutside demo modeRandom secret used by Better Auth. Generate at least 32 bytes.
APP_URLYes for email linksPublic application origin, including http:// or https://.
BETTER_AUTH_URLDeployed authOrigin Better Auth uses for auth links and OAuth callbacks.

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.

VariableDescription
GOOGLE_CLIENT_IDGoogle OAuth Web application client ID.
GOOGLE_CLIENT_SECRETGoogle OAuth client secret.
GITHUB_CLIENT_IDGitHub OAuth App client ID.
GITHUB_CLIENT_SECRETGitHub 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.

  1. Open Google Auth Platform in your Google Cloud project.
  2. Configure the app name, support email, homepage, privacy-policy URL, and authorized domain under Branding. Select an External audience for public customer access.
  3. 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.
  4. Store the client ID and secret as GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the server. Set APP_URL, BETTER_AUTH_URL, and any SPARKFEED_APP_ORIGIN override to the same application origin.
  5. 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.

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.

  1. Select the production Railway environment and the customer application service whose custom domain is app.sparkfeed.dev.
  2. Confirm that the deployment source includes the Google provider, provider discovery, and connected-account UI. Adding variables does not upload local code changes.
  3. Open Variables and add GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET as service variables. Enter both values directly in Railway. Do not paste them into chat, issue trackers, or committed files.
  4. 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.
  5. Set these non-secret variables for production:
APP_URL=https://app.sparkfeed.dev
BETTER_AUTH_URL=https://app.sparkfeed.dev
SPARKFEED_APP_ORIGIN=https://app.sparkfeed.dev
SPARKFEED_ENVIRONMENT=production
VITE_DEMO_MODE=false
  1. Leave VITE_AUTH_URL unset for the normal same-origin deployment. If an existing deployment sets it, confirm that it equals https://app.sparkfeed.dev.
  2. Keep the deployment’s existing BETTER_AUTH_SECRET and DATABASE_URL. The auth secret also encrypts stored OAuth tokens. Do not rotate it while adding Google credentials.
  3. 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.
  4. Wait for a successful deployment and the /api/health check. The repository’s Railway start command runs database migrations before starting the server. Check migration and startup logs if deployment fails.
  5. Open https://app.sparkfeed.dev/sign-in in 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.

  1. In GitHub Developer settings, register an OAuth App. For hosted production, use the name Sparkfeed-BetterAuth-Prod, homepage https://sparkfeed.dev, and exact redirect URI https://app.sparkfeed.dev/api/auth/callback/github.
  2. Leave wildcard matching and Device Flow disabled. Token expiry can stay enabled; Better Auth supports GitHub refresh tokens when issued.
  3. Generate a client secret. Add GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET to 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.
  4. Test sign-in with a GitHub account whose primary email is private, then connect and disconnect GitHub under Settings → Security. Better Auth requests read:user and user:email by 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.

  • 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_ORIGIN takes precedence over APP_URL and BETTER_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.

  • 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.

VariableDefaultDescription
ALLOW_REGISTRATIONfalseAllows public signup after the first account when set to true. A valid invitation still works when false.
WORKSPACE_CREATION_POLICYowner-onlyUse 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.

Set at least one provider key to enable Spark AI:

VariableProvider
OPENAI_API_KEYOpenAI
AI_GATEWAY_API_KEYVercel AI Gateway
OPENROUTER_API_KEYOpenRouter

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.

VariableDescription
RESEND_API_KEYResend credential.
SMTP_HOST, SMTP_PORTSMTP server.
SMTP_USER, SMTP_PASSSMTP credentials.
SMTP_SECURE, SMTP_IGNORE_TLSSMTP transport controls.

Without an email provider, verification, invitation, and password-reset messages cannot reach users.

Set VITE_DEMO_MODE before building and keep the same value at runtime:

VITE_DEMO_MODE=true

Demo mode ignores DATABASE_URL, uses rss-demo.db, bypasses auth, seeds sample content, and blocks mutations.