Skip to content

fix(auth): fail closed without JWT secret - #961

Open
nasalehj wants to merge 1 commit into
MettaChain:mainfrom
nasalehj:fix/issue-814-auth-secret-fail-closed
Open

fix(auth): fail closed without JWT secret#961
nasalehj wants to merge 1 commit into
MettaChain:mainfrom
nasalehj:fix/issue-814-auth-secret-fail-closed

Conversation

@nasalehj

Copy link
Copy Markdown

Summary

Closes #814

Protected-route middleware no longer verifies cookies with a committed fallback secret. Missing or blank AUTH_SECRET now follows the existing invalid-token redirect path, while configured secrets preserve the existing JWT verification and cookie-clearing behavior. Startup validation and environment documentation now require a server-side secret of at least 32 characters.

Why

Previously, any deployment with AUTH_SECRET unset accepted tokens signed with a public repository string, turning a missing configuration into an authentication bypass. The middleware now fails closed per request, and validation surfaces the configuration error before deployment.

What was built

File What it contains
middleware.ts Removes the hardcoded fallback and rejects missing/blank secrets before jwtVerify; preserves protected routes, clock tolerance, redirects, and invalid-cookie deletion.
scripts/validate-env.js Validates AUTH_SECRET as a trimmed string with at least 32 characters in development and the general environment schema.
.env.example Documents the server-only AUTH_SECRET configuration without including a usable value.
__tests__/middleware.test.ts Covers public/protected routes, valid/expired/tampered tokens, legacy fallback rejection, and missing/blank secret fail-closed behavior.
tests/helpers/middlewareJwtTestHelper.ts Test-only HS256 token helper used because the repository Jest transform cannot load the ESM jose package directly.
jest.config.cjs Includes the existing root __tests__ directory in Jest discovery so middleware coverage runs through the standard test command.

The tests use a local deterministic signing/verifying helper only to exercise middleware control flow under the current Jest environment; production middleware continues to use jose.

Integration changes outside src/

  • scripts/validate-env.js — rejects missing, empty, and short AUTH_SECRET values before deployment.
  • .env.example — documents the required server-side secret.
  • jest.config.cjs — makes the existing root middleware test discoverable by Jest.
  • tests/helpers/middlewareJwtTestHelper.ts — added test-only cryptographic fixture support; it is not imported by production code.

Acceptance criteria coverage

  • With AUTH_SECRET unset or empty, protected routes reject requests (redirect) instead of verifying with the fallback secret; with it set, normal verification behaves as today. (middleware.ts, __tests__/middleware.test.ts — 8/8 focused tests pass, including valid, missing, and blank secret cases)
  • The literal fallback string 'default-fallback-secret-for-dev-only-do-not-use-in-prod' is gone from middleware.ts. (middleware.ts and repository search — no occurrence remains in production middleware)
  • A test proves a token signed with the old fallback string is rejected when AUTH_SECRET is set, and that a missing AUTH_SECRET fails closed. (__tests__/middleware.test.ts — explicit legacy-secret and missing-secret tests)
  • npm run typecheck, npm test, and npm run lint pass. — Repository-wide gates remain blocked by pre-existing syntax errors, unrelated test failures, and missing eslint-plugin-jsdoc; focused middleware tests pass.

Deliberately deferred

  • None for the issue scope. Repository-wide quality gates are reported as blocked by baseline repository/tooling failures rather than deferred implementation work.

Test plan

  • npx prettier --check __tests__/middleware.test.ts tests/helpers/middlewareJwtTestHelper.ts middleware.ts scripts/validate-env.js — all matched files pass.
  • npm test -- --runInBand __tests__/middleware.test.ts — 8/8 passing.
  • AUTH_SECRET=test-secret-with-at-least-32-characters npm run validate:env — passes.
  • AUTH_SECRET= npm run validate:env — exits 1 with AUTH_SECRET: Invalid value.
  • npm run typecheck — fails on pre-existing syntax errors in unrelated files including src/app/compare/page.tsx, src/components/ComparisonBar.tsx, src/components/PropertyCard.tsx, src/components/TransactionConfirmation.tsx, src/lib/toast.ts, and src/stories/ResponsiveContainerExample.stories.ts; the baseline also reports an existing src/components/CartSidebar.tsx syntax error.
  • npm test -- --runInBand — 63/141 suites passing; 985/1152 tests passing. Failures are existing repository issues including incomplete viem mocks, Vitest/CommonJS incompatibilities, malformed unrelated source/tests, and unrelated component assertions.
  • npm run lint — cannot start because eslint-plugin-jsdoc is not installed.
  • npm run build — stops at the same pre-existing typecheck failures.

Env vars / Notes

AUTH_SECRET=

AUTH_SECRET must be supplied through the deployment secret manager or local uncommitted environment file and must contain at least 32 non-whitespace characters. No migration or API contract changes are included.

@drips-wave

drips-wave Bot commented Aug 26, 2026

Copy link
Copy Markdown

@nasalehj Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@nasalehj
nasalehj force-pushed the fix/issue-814-auth-secret-fail-closed branch from 0867bfd to 78b6fef Compare August 26, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

middleware.ts falls back to a hardcoded JWT secret: forged auth-token cookies verify when AUTH_SECRET is unset

1 participant