Fix/auto generate jwt secret - #94
Conversation
- Add ensureJwtSecret() in instrumentation.ts to generate random 64-char secret - Mark JWT_SECRET as non-required in secretsValidator - Remove fatal error log for missing JWT_SECRET in proxy.ts Fixes login failure when running via CLI without JWT_SECRET env var.
- Add setupComplete to settings validation schema for proper persistence - Support ?tab= query param in settings page for direct tab navigation - Redesign login page with professional two-column layout - Add context-aware states for onboarding/password setup flows - Smooth animations and refined visual hierarchy
Summary of ChangesHello @StealthIQ, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the application's initial setup and user experience by addressing critical authentication issues and streamlining the onboarding process. It introduces automatic JWT secret generation to ensure the application starts gracefully even without explicit configuration, and completely revamps the login page to provide contextual guidance to users based on their setup status. Additionally, it enhances UI navigation and consistency across various parts of the application. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request aims to simplify initial setup by auto-generating the JWT_SECRET and refining the login flow. However, a critical vulnerability has been identified in src/proxy.ts related to insecure JWT secret handling, which could lead to authentication bypass. Additionally, a high-severity privilege escalation flaw exists in src/shared/validation/schemas.ts, allowing authenticated users to reset the application's setup state and change the admin password. Beyond these security concerns, there are also issues with the persistence and propagation of the auto-generated secret, and the synchronization of settings page tabs with the URL.
| } | ||
|
|
||
| const SECRET = new TextEncoder().encode(process.env.JWT_SECRET); | ||
| const SECRET = new TextEncoder().encode(process.env.JWT_SECRET || ""); |
There was a problem hiding this comment.
The use of an empty string ("") as a fallback for the JWT_SECRET in src/proxy.ts is a critical vulnerability. If process.env.JWT_SECRET is missing or fails to propagate, the SECRET constant will be initialized with an empty value. This allows attackers to bypass authentication by forging tokens signed with an empty key, violating the "Fail Securely" principle. The secret should be loaded and validated within the request lifecycle, not at the module level. Initialize the secret inside the proxy function and add a check to ensure it is not empty, failing the request if it is.
| logRetentionDays: z.number().int().min(1).max(365).optional(), | ||
| cloudUrl: z.string().max(500).optional(), | ||
| baseUrl: z.string().max(500).optional(), | ||
| setupComplete: z.boolean().optional(), |
There was a problem hiding this comment.
Adding setupComplete to the updateSettingsSchema allows any authenticated user to modify this flag via the /api/settings endpoint. An attacker could set setupComplete: false, which reverts the application to its initial setup state. This re-enables the onboarding wizard, which allows setting a new admin password without requiring the current one. This could lead to a full account takeover by any authenticated user.
| setupComplete: z.boolean().optional(), | |
| // setupComplete: z.boolean().optional(), |
| if (!process.env.JWT_SECRET || process.env.JWT_SECRET.trim() === "") { | ||
| const generated = crypto.randomBytes(48).toString("base64"); | ||
| process.env.JWT_SECRET = generated; | ||
| console.log("[STARTUP] JWT_SECRET auto-generated (random 64-char secret)"); | ||
| } |
There was a problem hiding this comment.
The auto-generated secret is stored in process.env at runtime, which presents two major issues: 1. Persistence: The secret is lost on every server restart, invalidating all active user sessions and forcing logouts. 2. Propagation: In Next.js, environment variables modified in the Node.js runtime of instrumentation.ts do not reliably propagate to the Middleware (which often runs in the Edge runtime or a separate process). This means the Middleware might still see an undefined secret, leading to the authentication errors this PR intends to fix. Consider using a persistent storage mechanism or a stable machine-specific seed for zero-config setups.
* fix: auto-generate JWT_SECRET at startup if not provided - Add ensureJwtSecret() in instrumentation.ts to generate random 64-char secret - Mark JWT_SECRET as non-required in secretsValidator - Remove fatal error log for missing JWT_SECRET in proxy.ts Fixes login failure when running via CLI without JWT_SECRET env var. * feat: improve auth flow and login page UX - Add setupComplete to settings validation schema for proper persistence - Support ?tab= query param in settings page for direct tab navigation - Redesign login page with professional two-column layout - Add context-aware states for onboarding/password setup flows - Smooth animations and refined visual hierarchy * fix: 404 page to use primary color theme (coral red) instead of purple
Summary
JWT_SECRETused to trigger a fatal JWT verification failure. This PR fixes that issue by generating a fallback secret and cleans up the login flow so new users aren't hit with authentication errors right out of the gate.Changes
JWT Secret Auto-Generation
ensureJwtSecret()toinstrumentation.ts. It generates a random 64-character secret at startup if you don't provide one.JWT_SECRETas optional insecretsValidator.ts.proxy.ts.Login Flow
Settings & UI Tweaks
setupCompleteto the settings validation schema so state persists correctly.?tab=query parameter so you can link directly to specific tabs (e.g.,/dashboard/settings?tab=security).Files Changed
src/instrumentation.ts: Added auto-generation logic.src/proxy.ts: Removed fatal error.src/shared/utils/secretsValidator.ts: Updated validation rules.src/shared/validation/schemas.ts: AddedsetupComplete.src/app/login/page.tsx: Rewrote login UX.src/app/(dashboard)/dashboard/settings/page.tsx: Added query param support.src/app/not-found.tsx: Fixed theme colors.Testing
Tested locally. Verified the login flow works on a fresh CLI install without a secret, and that existing setups with secrets do not break. Checked all three login states (onboarding, password setup, standard).
Before / After
auth_errorifJWT_SECRETwas missing.Screenshots
Before: Login failed without JWT_SECRET
Middleware auth_error: JWT verification failed: signature verification failed
After: Auto-generated secret + contextual login
Users are guided through setup instead of hitting authentication errors.