Skip to content

Comments

security: move JWT secret to environment variable#660

Open
mmcintosh wants to merge 1 commit intoSonicJs-Org:mainfrom
mmcintosh:hotfix/jwt-secret-env
Open

security: move JWT secret to environment variable#660
mmcintosh wants to merge 1 commit intoSonicJs-Org:mainfrom
mmcintosh:hotfix/jwt-secret-env

Conversation

@mmcintosh
Copy link
Contributor

Security: Move JWT Secret to Environment Variable

Summary

Moves the hardcoded JWT signing secret out of source code and into an environment variable (JWT_SECRET). Falls back to the old hardcoded value for local development when no env var is set.

Changes

1. Environment-Based JWT Secret

  • generateToken() and verifyToken() accept an optional secret parameter
  • Secret is read from c.env.JWT_SECRET at every call site
  • Falls back to JWT_SECRET_FALLBACK (the old hardcoded value) when no env var is bound
  • Keeps local wrangler dev working without extra configuration

2. All Call Sites Updated

  • /auth/register -- pass c.env.JWT_SECRET
  • /auth/login -- pass c.env.JWT_SECRET
  • /auth/refresh -- pass c.env.JWT_SECRET
  • /auth/register/form -- pass c.env.JWT_SECRET
  • /auth/login/form -- pass c.env.JWT_SECRET
  • /auth/accept-invitation -- pass c.env.JWT_SECRET
  • Magic Link auth plugin -- pass (c.env as any).JWT_SECRET
  • OTP Login plugin -- pass (c.env as any).JWT_SECRET

3. Bindings Type Updated

  • Added JWT_SECRET?: string to the Bindings interface in app.ts

Technical Details

Core Changes:

  • packages/core/src/middleware/auth.ts -- generateToken(userId, email, role, secret?) and verifyToken(token, secret?) with env secret or fallback
  • packages/core/src/app.ts -- Added JWT_SECRET?: string to Bindings interface
  • packages/core/src/routes/auth.ts -- All 6 generateToken() calls pass c.env.JWT_SECRET

Plugin Updates:

  • packages/core/src/plugins/available/magic-link-auth/index.ts -- Pass env secret
  • packages/core/src/plugins/core-plugins/otp-login-plugin/index.ts -- Pass env secret

Testing

  • Unit Tests: PASSED (existing JWT tests use default fallback)
  • E2E Tests: PASSED (3/3 shards green)

Performance Impact

No performance impact -- same JWT library, same algorithm.

Breaking Changes

None. Without JWT_SECRET env var, behavior is identical to before.

Migration Notes

  • Production: Set via wrangler secret put JWT_SECRET with a strong random value (e.g., openssl rand -base64 32)
  • Local dev: Works without configuration (uses fallback)
  • Session impact: Changing the secret will invalidate all existing JWT tokens. Users will need to re-login.

Known Issues

None.

Demo / Screenshots

N/A -- no UI changes.

Related Issues

(Security hardening -- no linked issue)

Checklist

  • Code follows project coding standards
  • Tests added/updated and passing
  • Documentation updated
  • No breaking changes
  • Backward compatible

}

it('valid key with matching scope — calls next()', async () => {
const hash = await hashApiKey(TOKEN)

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable hash.
})

const mw = requireApiKey('search:read')
const result = await mw(ctx, mockNext)

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable result.
- Add optional secret parameter to generateToken/verifyToken
- Falls back to hardcoded constant for local dev without wrangler secret
- Add JWT_SECRET to Bindings interface
- Update all generateToken callsites to pass c.env.JWT_SECRET
- Update requireAuth and optionalAuth middleware to pass env secret
- Update magic-link-auth and otp-login plugins

Production: set via `wrangler secret put JWT_SECRET`

Fixes VULN-001
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.

1 participant