Skip to content

fix: remove hardcoded JWT secrets, add auth guards, and implement password reset - #1363

Merged
yusuftomilola merged 3 commits into
DistinctCodes:mainfrom
OladipupuHussein7:feature/auth-security-hardening
Aug 26, 2026
Merged

fix: remove hardcoded JWT secrets, add auth guards, and implement password reset#1363
yusuftomilola merged 3 commits into
DistinctCodes:mainfrom
OladipupuHussein7:feature/auth-security-hardening

Conversation

@OladipupuHussein7

@OladipupuHussein7 OladipupuHussein7 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR addresses three critical authentication and security issues:

BE-111: Hardcoded fallback JWT secrets in AuthService and JwtStrategy

  • Removed all hardcoded fallback secrets from auth.service.ts, jwt.strategy.ts, and auth.module.ts
  • App now fails fast at startup with a descriptive error if JWT_SECRET or JWT_REFRESH_SECRET are missing or shorter than 32 characters
  • No source file contains a literal fallback secret anymore

BE-112: Twelve controllers have no authentication guard at all

  • Added @UseGuards(JwtAuthGuard) to all 12 unguarded controllers:
    • branches, vendors, purchase-orders, transfers, departments, categories, locations, inventory, audits, maintenance, asset-maintenance, licenses, notes-docs
  • Every route on these controllers now requires a valid JWT token

BE-113: AuthService.forgotPassword() is a no-op stub; there is no resetPassword endpoint

  • forgotPassword() now generates a cryptographically random, single-use, time-limited (1 hour) reset token
  • Token is hashed and stored on the User entity with an expiry timestamp
  • Added POST /auth/reset-password endpoint that validates and consumes the token
  • Reset tokens are automatically invalidated when the user changes their password via updateMe()

Closes #1253
Closes #1254
Closes #1255
Closed #1120

…sword reset

- BE-111: Removed all hardcoded fallback JWT secrets from AuthService, JwtStrategy, and AuthModule; app now fails at startup if JWT_SECRET or JWT_REFRESH_SECRET are missing or too short
- BE-112: Added @UseGuards(JwtAuthGuard) to all 12 unguarded controllers (branches, vendors, purchase-orders, transfers, departments, categories, locations, inventory, audits, maintenance, asset-maintenance, licenses, notes-docs)
- BE-113: Implemented full password reset flow: forgotPassword generates a hashed, time-limited token stored on the User entity; resetPassword validates and consumes the token; POST /auth/reset-password endpoint added; tokens invalidated on password change

Closes DistinctCodes#1253
Closes DistinctCodes#1254
Closes DistinctCodes#1255
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

@OladipupuHussein7 is attempting to deploy a commit to the naijabuz's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 25, 2026

Copy link
Copy Markdown

@OladipupuHussein7 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

forgotPassword() returned the raw resetToken directly in the JSON
response with only a comment noting it should be emailed instead.
As written, anyone who knows a user's email could call this endpoint,
read the token back, and take over the account via resetPassword() -
an unauthenticated account-takeover path with no gating.

Gate the token behind NODE_ENV !== 'production', matching the
existing convention in main.ts for the Swagger docs gate. Dev/test
flows that rely on reading the token back from this response keep
working; production callers get only the generic message until real
email delivery is wired up.
Resolve import-line conflicts in branches.controller.ts and
purchase-orders.controller.ts against already-merged DistinctCodes#1361 (Patch/
Delete/Req imports vs. this PR's UseGuards import) - both sets are
needed, so combined them. transfers.controller.ts merged cleanly.

@yusuftomilola yusuftomilola left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Strong security hardening overall:

  • Removed hardcoded fallback JWT secrets ('secretKey' / 'refreshSecretKey') from auth.service.ts, auth.module.ts, and jwt.strategy.ts — previously anyone could forge valid tokens using the well-known default if the env var was ever unset. Now main.ts fails fast at boot if JWT_SECRET/JWT_REFRESH_SECRET are missing or under 32 characters, so the app can no longer run with a weak/missing secret.
  • Real password-reset flow: random 32-byte token, hashed before storage, 1-hour expiry checked on use, bcrypt for the new password, and the reset token is cleared after use or after a normal password change.
  • @UseGuards(JwtAuthGuard) added to branches, categories, departments, inventory, licenses, locations, maintenance, audits, notes-docs, transfers, purchase-orders, and vendors controllers — these were previously reachable with no authentication at all.

Found and fixed one issue before merging: forgotPassword() was returning the raw resetToken directly in the API response in all environments (comment said 'In production, send via email' but nothing gated it) — that's an unauthenticated account-takeover path for anyone who knows a user's email. Pushed a fix gating the token behind NODE_ENV !== 'production', matching the existing Swagger-gating convention in main.ts. Also worth a follow-up (not fixed here, lower severity): forgotPassword currently 404s for unknown emails vs 200 for known ones, which lets an attacker enumerate registered emails — the common fix is to return the same generic response either way.

Approving.

@yusuftomilola
yusuftomilola merged commit 41bdfae into DistinctCodes:main Aug 26, 2026
6 of 10 checks passed
yusuftomilola added a commit to devzakari-sketch/AssetsUp that referenced this pull request Aug 26, 2026
…-pagination

Resolve import/method conflicts against DistinctCodes#1361 (branches delete, PO
cancel, transfers cancel/complete) and DistinctCodes#1363 (JwtAuthGuard on
branches/departments/purchase-orders/transfers/vendors) - all
additive, combined both sides. purchase-orders.service.ts findAll
now paginates AND still eager-loads lineItems (was dropped by the
pagination rewrite otherwise).

Also fixes a compile bug: create-purchase-order.dto.ts imported and
used @isMin(0), which does not exist in class-validator (the correct
decorator is @min, as already used elsewhere in this exact repo's
pagination.dto.ts). Renamed to @min(0).
yusuftomilola added a commit that referenced this pull request Aug 26, 2026
…-vendors-licenses-dtos-pagination

Merging per repo maintainer review. Resolved conflicts against #1361 and #1363 (all additive), and fixed a real compile bug (@isMin doesn't exist in class-validator, renamed to @min) before merging. Pre-existing CI failures otherwise predate this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants