From 047a92cda0ab36aff22ec4db3776aa53e170cae2 Mon Sep 17 00:00:00 2001 From: Pierre Brisorgueil Date: Mon, 9 Mar 2026 08:55:44 +0100 Subject: [PATCH 1/2] feat(auth): add public GET /api/auth/config endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose auth feature flags (sign.in, sign.up) so the Vue frontend can display a warning when signin/signup is disabled server-side. Only boolean flags are returned — no secrets exposed. --- modules/auth/controllers/auth.controller.js | 16 ++++++++++++++++ modules/auth/routes/auth.routes.js | 3 +++ 2 files changed, 19 insertions(+) diff --git a/modules/auth/controllers/auth.controller.js b/modules/auth/controllers/auth.controller.js index 91ed5f3d5..48e27c008 100644 --- a/modules/auth/controllers/auth.controller.js +++ b/modules/auth/controllers/auth.controller.js @@ -207,6 +207,21 @@ const oauthCallback = async (req, res, next) => { })(req, res, next); }; +/** + * @desc Endpoint to expose public auth feature flags + * @param {Object} req - Express request object + * @param {Object} res - Express response object + * @returns {Object} Public auth configuration (sign and oAuth flags only) + */ +const getConfig = (_req, res) => { + responses.success(res, 'Auth config')({ + sign: { + in: !!config.sign.in, + up: !!config.sign.up, + }, + }); +}; + export default { signup, signin, @@ -214,4 +229,5 @@ export default { oauthCall, oauthCallback, checkOAuthUserProfile, + getConfig, }; diff --git a/modules/auth/routes/auth.routes.js b/modules/auth/routes/auth.routes.js index 73fde70a1..f585bf1bd 100644 --- a/modules/auth/routes/auth.routes.js +++ b/modules/auth/routes/auth.routes.js @@ -13,6 +13,9 @@ import authPassword from '../controllers/auth.password.controller.js'; export default (app) => { const authLimiter = rateLimit(config.rateLimit.auth); + // Public auth config (no authentication required, rate-limited) + app.route('/api/auth/config').get(authLimiter, auth.getConfig); + // Setting up the users password api app.route('/api/auth/forgot').post(authLimiter, authPassword.forgot); app.route('/api/auth/reset/:token').get(authLimiter, authPassword.validateResetToken); From f2e835a30022a3c507bb1f4e2584238a06533eda Mon Sep 17 00:00:00 2001 From: Pierre Brisorgueil Date: Mon, 9 Mar 2026 09:03:29 +0100 Subject: [PATCH 2/2] fix(auth): address review feedback from pass 1 --- modules/auth/controllers/auth.controller.js | 4 +-- modules/auth/tests/auth.integration.tests.js | 28 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/modules/auth/controllers/auth.controller.js b/modules/auth/controllers/auth.controller.js index 48e27c008..933f90afa 100644 --- a/modules/auth/controllers/auth.controller.js +++ b/modules/auth/controllers/auth.controller.js @@ -208,10 +208,10 @@ const oauthCallback = async (req, res, next) => { }; /** - * @desc Endpoint to expose public auth feature flags + * @desc Endpoint to expose public auth sign-in/up feature flags * @param {Object} req - Express request object * @param {Object} res - Express response object - * @returns {Object} Public auth configuration (sign and oAuth flags only) + * @returns {void} Sends the public auth configuration (sign flags only) in the HTTP response */ const getConfig = (_req, res) => { responses.success(res, 'Auth config')({ diff --git a/modules/auth/tests/auth.integration.tests.js b/modules/auth/tests/auth.integration.tests.js index d33ea74e7..4bf1cfd0f 100644 --- a/modules/auth/tests/auth.integration.tests.js +++ b/modules/auth/tests/auth.integration.tests.js @@ -804,6 +804,34 @@ describe('Auth integration tests:', () => { }); }); + describe('Config endpoint', () => { + test('should return sign flags reflecting current config', async () => { + const result = await agent.get('/api/auth/config').expect(200); + expect(result.body.data).toEqual({ + sign: { + in: expect.any(Boolean), + up: expect.any(Boolean), + }, + }); + }); + + test('should return false when sign.up is disabled', async () => { + const original = config.sign.up; + config.sign.up = false; + const result = await agent.get('/api/auth/config').expect(200); + expect(result.body.data.sign.up).toBe(false); + config.sign.up = original; + }); + + test('should return false when sign.in is disabled', async () => { + const original = config.sign.in; + config.sign.in = false; + const result = await agent.get('/api/auth/config').expect(200); + expect(result.body.data.sign.in).toBe(false); + config.sign.in = original; + }); + }); + // Mongoose disconnect afterAll(async () => { try {