Add embeddable Auth module with JWT sessions, DB init, middleware and tests - #3
Closed
darkooom wants to merge 1 commit into
Closed
Add embeddable Auth module with JWT sessions, DB init, middleware and tests#3darkooom wants to merge 1 commit into
darkooom wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Several verified issues affect embeddability/security/behavior consistency (dotenv side effects, API-key comparison, mailer transporter caching, email-verification flag handling, and inconsistent Argon2id usage).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR restructures the project into an embeddable Express authentication module with PostgreSQL-backed sessions, JWT access/refresh tokens (with rotation), configurable middleware, schema initialization, and a standalone server entrypoint for running it as an API.
Changes:
- Added
createAuthModule()(auth-module.js) exposing a mountable router, initialization/close hooks, and reusable middleware exports. - Implemented auth utilities (JWT/token hashing, one-time tokens, validation), mail delivery, and configuration validation.
- Reworked DB access around a
pgPool, added idempotent schema initialization, rebuilt auth/admin routes, and introduced unit tests + updated docs/env/examples.
File summaries
| File | Description |
|---|---|
| utils/validateConfig.js | Adds config validation for required secrets/SMTP and DB env requirements. |
| utils/mailer.js | Introduces Nodemailer-based mail helper for auth flows. |
| utils/initDatabase.js | Adds idempotent schema/table/index initialization for users/tokens. |
| utils/database.js | Migrates DB layer to pg.Pool with injectable pool support and close hook. |
| utils/config.js | Adds config defaults + env/options merge via configure()/getConfig(). |
| utils/auth/validation.js | Adds username/email normalization + password policy validation helpers. |
| utils/auth/tokens.js | Adds JWT access/refresh token build/verify helpers and token hashing. |
| utils/auth/oneTimeTokens.js | Adds one-time token generation + hashing helpers. |
| test/auth-utils.test.js | Adds unit tests for tokens, validation, config, and module embedding. |
| routes/main.js | Updates root/health endpoints to expose status metadata. |
| routes/auth/session.js | Adds refresh/rotation, logout, profile, session management, password change flows. |
| routes/auth/router.js | Composes auth subroutes with API-key middleware + rate limiting. |
| routes/auth/register.js | Replaces unsafe SQL with parameterized registration + email verification token issuing. |
| routes/auth/recovery.js | Adds verify-email + resend + forgot/reset password one-time-token flows. |
| routes/auth/login.js | Adds login via username/email with refresh-token persistence and JWT issuance. |
| routes/admin/index.js | Rebuilds admin API with API-key auth + bearer auth + DB-backed role authorization. |
| README.md | Documents embeddable module usage, security features, and endpoint inventory. |
| package.json | Updates package entry/exports, scripts, and dependencies for module consumption/testing. |
| package-lock.json | Updates lockfile to new dependency graph and lockfile v3. |
| middleware/validateApiKey.js | Adds API key enforcement middleware for auth/admin routes. |
| middleware/rateLimiters.js | Adds shared rate-limit middleware for auth and credential endpoints. |
| middleware/index.js | Exposes middleware bundle via package export. |
| middleware/authorize.js | Adds role-based authorization with DB check per request. |
| middleware/authenticate.js | Adds bearer-token authentication middleware for access tokens. |
| index.js | Updates standalone server wiring: CORS allowlist, security headers, router mounting, startup init. |
| auth-module.js | Implements embeddable module factory integrating config/db init/middleware/routers. |
| .env.example | Adds documented env defaults including JWT, SMTP, CORS, DB pool settings. |
Review details
- Files reviewed: 26/27 changed files
- Comments generated: 6
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| @@ -1,22 +1,37 @@ | |||
| require('dotenv').config(); | |||
Comment on lines
+1
to
+22
| const { getConfig } = require('../utils/config'); | ||
|
|
||
| const validateApiKey = (req, res, next) => { | ||
| const incomingApiKey = req.header('x-api-key'); | ||
| const { apiKey } = getConfig(); | ||
|
|
||
| if (!apiKey) { | ||
| return res.status(500).json({ | ||
| message: 'API key protection is not configured on this server.', | ||
| }); | ||
| } | ||
|
|
||
| if (!incomingApiKey || incomingApiKey !== apiKey) { | ||
| return res.status(401).json({ | ||
| message: 'Invalid API key.', | ||
| }); | ||
| } | ||
|
|
||
| return next(); | ||
| }; | ||
|
|
||
| module.exports = validateApiKey; |
Comment on lines
+4
to
+18
| let transporter; | ||
|
|
||
| const getTransporter = () => { | ||
| const { smtp } = getConfig(); | ||
| if (!smtp?.host) return null; | ||
| if (!transporter) { | ||
| transporter = nodemailer.createTransport({ | ||
| host: smtp.host, | ||
| port: Number(smtp.port || 587), | ||
| secure: smtp.secure === true, | ||
| auth: smtp.user ? { user: smtp.user, pass: smtp.pass } : undefined, | ||
| }); | ||
| } | ||
| return transporter; | ||
| }; |
Comment on lines
+43
to
+65
| const createdUser = await db.query( | ||
| `INSERT INTO users (username, email, password) | ||
| VALUES ($1, $2, $3) | ||
| RETURNING id, username, email, role, email_verified_at, created_at`, | ||
| [username, email, passwordHash], | ||
| ); | ||
|
|
||
| const user = createdUser.rows[0]; | ||
| const verificationToken = createOneTimeToken(); | ||
| await db.query( | ||
| `INSERT INTO one_time_tokens (user_id, purpose, token_hash, expires_at) | ||
| VALUES ($1, 'verify_email', $2, NOW() + INTERVAL '24 hours')`, | ||
| [user.id, hashOneTimeToken(verificationToken)], | ||
| ); | ||
| const config = getConfig(); | ||
| const verifyUrl = `${config.appUrl}/verify-email?token=${encodeURIComponent(verificationToken)}`; | ||
| await sendAuthEmail({ to: email, subject: 'Verify your email', text: `Verify your email address: ${verifyUrl}` }); | ||
|
|
||
| return res.status(201).json({ | ||
| message: 'User created successfully. Please verify your email address.', | ||
| user, | ||
| ...(config.nodeEnv !== 'production' && { verificationToken }), | ||
| }); |
Comment on lines
+5
to
+9
| return res.status(200).json({ | ||
| message: 'Auth API is running.', | ||
| version: '2.0.0', | ||
| docs: '/README.md', | ||
| }); |
| return res.status(401).json({ message: 'Current password is incorrect.' }); | ||
| } | ||
|
|
||
| const hash = await argon2.hash(newPassword); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
README.mdand.env.example.Description
createAuthModule()inauth-module.jswhich returns a mountablerouter, aninitialize()function, middleware bundle andclose(); addsexportstopackage.json.utils/auth/tokens.js), one-time token helpers (utils/auth/oneTimeTokens.js), validation helpers (utils/auth/validation.js), mailer (utils/mailer.js), config handling (utils/config.js) and config validator (utils/validateConfig.js).pgPoolwithutils/initDatabase.jsthat idempotently creates tables/indices and exposes ausePool()/close()API inutils/database.js.routes/auth/*,routes/admin/*androutes/main.js, plus new middleware (middleware/*) forauthenticate,authorize,validateApiKeyand rate limiters.index.js) to embed the auth router, wire initialization and provide error/404 handlers; updatesREADME.md,.env.example,package.jsonand dependency lockfile.Testing
test/auth-utils.test.jsexercising token generation/verification, validation rules and embedding viacreateAuthModule()and ran them withnpm test(which usesnode --test), and they passed.npm run checkto verify JS file syntax, and it completed without errors.Codex Task