From 20be9543688c4fbb1eabd03f69072e83ce1878ae Mon Sep 17 00:00:00 2001 From: ksjaay Date: Sun, 30 Nov 2025 19:37:46 +0000 Subject: [PATCH 1/2] Adds support for custom oauth systems --- .../modal/monitor/pages/initial/parent.tsx | 4 + .../settings/authentication/configure.tsx | 55 +++++- app/types/context/authentication.d.ts | 8 +- package-lock.json | 170 +----------------- package.json | 3 +- server/database/queries/provider.js | 2 +- server/middleware/auth/callback/custom.js | 36 +++- server/middleware/auth/platform.js | 3 +- server/middleware/provider/getAll.js | 10 +- server/routes/auth.js | 2 +- server/routes/user.js | 4 +- shared/constants/provider.js | 12 +- shared/utils/authenication.js | 19 +- 13 files changed, 135 insertions(+), 193 deletions(-) diff --git a/app/components/modal/monitor/pages/initial/parent.tsx b/app/components/modal/monitor/pages/initial/parent.tsx index ea2bff9a..4dd7b4f5 100644 --- a/app/components/modal/monitor/pages/initial/parent.tsx +++ b/app/components/modal/monitor/pages/initial/parent.tsx @@ -58,6 +58,10 @@ const MonitorParentSelect = ({ key={monitor.monitorId} onClick={() => onSelect(monitor.monitorId)} > + {monitor.name} ))} diff --git a/app/components/modal/settings/authentication/configure.tsx b/app/components/modal/settings/authentication/configure.tsx index 8d32489a..95983665 100644 --- a/app/components/modal/settings/authentication/configure.tsx +++ b/app/components/modal/settings/authentication/configure.tsx @@ -24,7 +24,12 @@ const SettingsAuthenticationConfigureModal = ({ const [values, setValues] = useState({ clientId: provider?.clientId || '', clientSecret: provider?.clientSecret || '', + authUrl: provider?.data?.authUrl || '', + tokenUrl: provider?.data?.tokenUrl || '', + userInfoUrl: provider?.data?.userInfoUrl || '', + name: provider?.data?.name || '', }); + const currentUrl = useCurrentUrl(); const { addProvider } = useAuthenticationContext(); @@ -35,7 +40,12 @@ const SettingsAuthenticationConfigureModal = ({ clientId: values.clientId, clientSecret: values.clientSecret, enabled: true, - data: {}, + data: { + tokenUrl: values.tokenUrl, + name: values.name, + authUrl: values.authUrl, + userInfoUrl: values.userInfoUrl, + }, }; const provider = await createPostRequest( @@ -70,6 +80,49 @@ const SettingsAuthenticationConfigureModal = ({ } onClose={closeModal} > + {integration.id === 'custom' && ( + <> + ) => + setValues((prev) => ({ ...prev, name: e.target.value })) + } + isRequired + /> + + ) => + setValues((prev) => ({ ...prev, authUrl: e.target.value })) + } + isRequired + /> + + ) => + setValues((prev) => ({ ...prev, tokenUrl: e.target.value })) + } + isRequired + /> + + ) => + setValues((prev) => ({ ...prev, userInfoUrl: e.target.value })) + } + isRequired + /> + + )} =10" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -8483,17 +8462,6 @@ "node": ">=8" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -9227,6 +9195,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -10079,12 +10048,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lossless-json": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lossless-json/-/lossless-json-4.1.1.tgz", - "integrity": "sha512-HusN80C0ohtT9kOHQH7EuUaqzRQsnekpa+2ot8OzvW0iC08dq/YtM/7uKwwajldQsCrHyC8q9fz3t3L+TmDltA==", - "license": "MIT" - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -10287,6 +10250,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10494,17 +10458,6 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/node-mocks-http": { "version": "1.17.2", "resolved": "https://registry.npmjs.org/node-mocks-http/-/node-mocks-http-1.17.2.tgz", @@ -10978,15 +10931,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -12588,12 +12532,6 @@ "node": ">= 10.x" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" - }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -13127,54 +13065,6 @@ "tree-kill": "cli.js" } }, - "node_modules/tree-sitter": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz", - "integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^8.0.0", - "node-gyp-build": "^4.8.0" - } - }, - "node_modules/tree-sitter-bash": { - "version": "0.23.3", - "resolved": "https://registry.npmjs.org/tree-sitter-bash/-/tree-sitter-bash-0.23.3.tgz", - "integrity": "sha512-36cg/GQ2YmIbeiBeqeuh4fBJ6i4kgVouDaqTxqih5ysPag+zHufyIaxMOFeM8CeplwAK/Luj1o5XHqgdAfoCZg==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^8.2.1", - "node-gyp-build": "^4.8.2" - }, - "peerDependencies": { - "tree-sitter": "^0.21.1" - }, - "peerDependenciesMeta": { - "tree-sitter": { - "optional": true - } - } - }, - "node_modules/tree-sitter-bash/node_modules/node-addon-api": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz", - "integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==", - "license": "MIT", - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, - "node_modules/tree-sitter/node_modules/node-addon-api": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.4.0.tgz", - "integrity": "sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg==", - "license": "MIT", - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -13875,12 +13765,6 @@ "node": ">=0.10.0" } }, - "node_modules/web-tree-sitter": { - "version": "0.24.7", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.7.tgz", - "integrity": "sha512-CdC/TqVFbXqR+C51v38hv6wOPatKEUGxa39scAeFSm98wIhZxAYonhRQPSMmfZ2w7JDI0zQDdzdmgtNk06/krQ==", - "license": "MIT" - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -14124,50 +14008,6 @@ "node": ">= 14.6" } }, - "node_modules/yamljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", - "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "glob": "^7.0.5" - }, - "bin": { - "json2yaml": "bin/json2yaml", - "yaml2json": "bin/yaml2json" - } - }, - "node_modules/yamljs/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/yamljs/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 8ed274e5..fb31b0f8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lunalytics", - "version": "0.10.13", + "version": "0.10.14", "description": "Open source Node.js server/website monitoring tool", "private": true, "author": "KSJaay ", @@ -55,7 +55,6 @@ "cors": "2.8.5", "cron": "4.3.1", "cross-env": "7.0.3", - "curlconverter": "4.12.0", "dayjs": "1.11.13", "express": "4.21.2", "i18next": "25.3.2", diff --git a/server/database/queries/provider.js b/server/database/queries/provider.js index 4eb3f6af..d872b0f3 100644 --- a/server/database/queries/provider.js +++ b/server/database/queries/provider.js @@ -17,7 +17,7 @@ export const fetchProvider = async (provider) => { .where({ provider }) .first(); - return providerData; + return { ...providerData, data: JSON.parse(providerData?.data || '{}') }; }; export const fetchProviders = async () => { diff --git a/server/middleware/auth/callback/custom.js b/server/middleware/auth/callback/custom.js index 458fd872..48c485e7 100644 --- a/server/middleware/auth/callback/custom.js +++ b/server/middleware/auth/callback/custom.js @@ -2,20 +2,25 @@ import axios from 'axios'; // import local files -import { getAuthCallbackUrl } from '../../../../shared/utils/authenication.js'; -import { fetchProvider } from '../../../database/queries/provider.js'; import config from '../../../utils/config.js'; +import { fetchProvider } from '../../../database/queries/provider.js'; +import { handleError } from '../../../utils/errors.js'; +import { getAuthCallbackUrl } from '../../../../shared/utils/authenication.js'; -const customCallback = async (request, response) => { +const customCallback = async (request, response, next) => { try { const { code } = request.query; - if (!code) return response.status(400).send('No code provided'); + if (!code) { + return response.redirect('/error?code=missing_code&provider=custom'); + } const provider = await fetchProvider('custom'); if (!provider) { - return response.redirect('/auth/error'); + return response.redirect( + '/auth/error?code=provider_not_found&provider=custom' + ); } const websiteUrl = config.get('websiteUrl'); @@ -28,17 +33,30 @@ const customCallback = async (request, response) => { `${websiteUrl}/api/auth/callback/custom` ); - const { data } = await axios.post(...params); + const { data } = await axios.post(provider.data.tokenUrl, ...params); const { access_token } = data; - const userInfo = await axios.get('https://custom-provider.com/api/user', { + const userInfoResponse = await axios.get(provider.data.userInfoUrl, { headers: { Authorization: `Bearer ${access_token}` }, }); - return response.send(userInfo.data); + const user = userInfoResponse.data; + if (!user || !user.email) { + return response.redirect('/error?code=unverified_user&provider=custom'); + } + + response.locals.authUser = { + id: user.id || user.sub, + email: user.email, + avatar: user.avatar || user.picture, + username: user.username || user.name || 'unknown', + provider: 'custom', + }; + + return next(); } catch (error) { - console.log(error); + handleError(error, response); } }; diff --git a/server/middleware/auth/platform.js b/server/middleware/auth/platform.js index 56498a17..982732aa 100644 --- a/server/middleware/auth/platform.js +++ b/server/middleware/auth/platform.js @@ -19,7 +19,8 @@ const redirectUsingProviderMiddleware = async (request, response) => { const redirectUrl = getAuthRedirectUrl( provider.provider, provider.clientId, - `${websiteUrl}/api/auth/callback/${provider.provider}` + `${websiteUrl}/api/auth/callback/${provider.provider}`, + provider.data?.authUrl ); return response.redirect(redirectUrl); diff --git a/server/middleware/provider/getAll.js b/server/middleware/provider/getAll.js index 5717b51c..2107eb00 100644 --- a/server/middleware/provider/getAll.js +++ b/server/middleware/provider/getAll.js @@ -4,9 +4,15 @@ import { fetchProviders } from '../../database/queries/provider.js'; const getAllProvidersMiddleware = async (request, response) => { try { const query = await fetchProviders(); - response.json(query); + + const providers = query.map((provider) => ({ + ...provider, + data: provider.data ? JSON.parse(provider.data) : {}, + })); + + return response.json(providers); } catch (error) { - handleError(error, response); + return handleError(error, response); } }; diff --git a/server/routes/auth.js b/server/routes/auth.js index f544f2b6..a3cfbe66 100644 --- a/server/routes/auth.js +++ b/server/routes/auth.js @@ -24,7 +24,7 @@ router.post('/login', login); router.get('/logout', logout); router.get('/platform/:provider', redirectUsingProviderMiddleware); -router.get('/callback/custom', customCallback); +router.get('/callback/custom', customCallback, signInOrRegisterUsingAuth); router.get('/callback/discord', discordCallback, signInOrRegisterUsingAuth); router.get('/callback/github', githubCallback, signInOrRegisterUsingAuth); router.get('/callback/google', googleCallback, signInOrRegisterUsingAuth); diff --git a/server/routes/user.js b/server/routes/user.js index a8788234..c0bcadf8 100644 --- a/server/routes/user.js +++ b/server/routes/user.js @@ -24,6 +24,8 @@ router.get('/', fetchUserMiddleware); router.post('/exists', userExistsMiddleware); +router.post('/delete/account', deleteAccountMiddleware); + router.get( '/monitors', hasRequiredPermission(PermissionsBits.VIEW_MONITORS), @@ -58,6 +60,4 @@ router.post('/permission/update', permissionUpdateMiddleware); router.post('/transfer/ownership', transferOwnershipMiddleware); -router.post('/delete/account', deleteAccountMiddleware); - export default router; diff --git a/shared/constants/provider.js b/shared/constants/provider.js index 42ce7a0d..47479e6e 100644 --- a/shared/constants/provider.js +++ b/shared/constants/provider.js @@ -1,10 +1,10 @@ export const providers = [ - // { - // id: 'custom', - // name: 'Custom Provider', - // description: 'Setup a custom provider like Authentik, Keycloak, etc.', - // icon: '/logo.svg', - // }, + { + id: 'custom', + name: 'Custom Provider', + description: 'Setup a custom provider like Authentik, Keycloak, etc.', + icon: '/logo.svg', + }, { id: 'discord', name: 'Discord', diff --git a/shared/utils/authenication.js b/shared/utils/authenication.js index b790d34c..c6418d66 100644 --- a/shared/utils/authenication.js +++ b/shared/utils/authenication.js @@ -1,4 +1,9 @@ -export const getAuthRedirectUrl = (provider, clientId, redirectUri) => { +export const getAuthRedirectUrl = ( + provider, + clientId, + redirectUri, + authUrl +) => { const queryParams = { client_id: clientId, redirect_uri: redirectUri, @@ -67,6 +72,10 @@ export const getAuthRedirectUrl = (provider, clientId, redirectUri) => { } if (provider === 'custom') { + queryParams.response_type = 'code'; + queryParams.scope = 'openid profile email'; + + return authUrl + '?' + new URLSearchParams(queryParams).toString(); } return null; @@ -145,7 +154,13 @@ export const getAuthCallbackUrl = ( } if (provider === 'custom') { - return []; + return [ + new URLSearchParams({ + ...queryParams, + grant_type: 'authorization_code', + }).toString(), + { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }, + ]; } return null; From 821fdcc26fa44451b25371e3cdca5ff97c7a2259 Mon Sep 17 00:00:00 2001 From: ksjaay Date: Mon, 1 Dec 2025 18:42:31 +0000 Subject: [PATCH 2/2] Updates the tests for auth endpoints --- .../middleware/auth/callback/custom.test.js | 64 +++++++++++++++---- test/server/middleware/auth/platform.test.js | 3 +- .../server/middleware/provider/getAll.test.js | 4 +- 3 files changed, 56 insertions(+), 15 deletions(-) diff --git a/test/server/middleware/auth/callback/custom.test.js b/test/server/middleware/auth/callback/custom.test.js index b1416404..554aee3e 100644 --- a/test/server/middleware/auth/callback/custom.test.js +++ b/test/server/middleware/auth/callback/custom.test.js @@ -10,51 +10,89 @@ vi.mock('../../../../../server/utils/config.js'); describe('customCallback', () => { let fakeRequest, fakeResponse; + let next; beforeEach(() => { fakeRequest = createRequest(); fakeResponse = createResponse(); - fakeRequest.query = { code: 'abc' }; fakeResponse.redirect = vi.fn(); - fakeResponse.status = vi.fn().mockReturnThis(); - fakeResponse.send = vi.fn(); fakeResponse.locals = {}; + next = vi.fn(); }); afterEach(() => { vi.clearAllMocks(); }); - it('should return 400 if no code provided', async () => { + it('should redirect if no code provided', async () => { fakeRequest.query.code = undefined; - await customCallback(fakeRequest, fakeResponse); + await customCallback(fakeRequest, fakeResponse, next); - expect(fakeResponse.status).toHaveBeenCalledWith(400); - expect(fakeResponse.send).toHaveBeenCalledWith('No code provided'); + expect(fakeResponse.redirect).toHaveBeenCalledWith( + '/error?code=missing_code&provider=custom' + ); + expect(next).not.toHaveBeenCalled(); }); it('should redirect if provider not found', async () => { fetchProvider.mockResolvedValue(null); - await customCallback(fakeRequest, fakeResponse); + await customCallback(fakeRequest, fakeResponse, next); - expect(fakeResponse.redirect).toHaveBeenCalledWith('/auth/error'); + expect(fakeResponse.redirect).toHaveBeenCalledWith( + '/auth/error?code=provider_not_found&provider=custom' + ); + expect(next).not.toHaveBeenCalled(); }); - it('should send userInfo if provider and code are valid', async () => { + it('should set authUser and call next if provider and code are valid', async () => { fetchProvider.mockResolvedValue({ provider: 'custom', clientId: 'id', clientSecret: 'secret', + data: { + tokenUrl: 'https://site.com/token', + userInfoUrl: 'https://site.com/userinfo', + }, }); config.get.mockReturnValue('https://site.com'); axios.post.mockResolvedValue({ data: { access_token: 'token' } }); - axios.get.mockResolvedValue({ data: { id: 'i', email: 'e' } }); + axios.get.mockResolvedValue({ + data: { id: 'i', email: 'e', avatar: 'a', username: 'u' }, + }); + + await customCallback(fakeRequest, fakeResponse, next); + + expect(fakeResponse.locals.authUser).toEqual({ + id: 'i', + email: 'e', + avatar: 'a', + username: 'u', + provider: 'custom', + }); + expect(next).toHaveBeenCalled(); + }); + it('should redirect if user info is missing or email is not present', async () => { + fetchProvider.mockResolvedValue({ + provider: 'custom', + clientId: 'id', + clientSecret: 'secret', + data: { + tokenUrl: 'https://site.com/token', + userInfoUrl: 'https://site.com/userinfo', + }, + }); + config.get.mockReturnValue('https://site.com'); + axios.post.mockResolvedValue({ data: { access_token: 'token' } }); + axios.get.mockResolvedValue({ data: {} }); - await customCallback(fakeRequest, fakeResponse); + await customCallback(fakeRequest, fakeResponse, next); - expect(fakeResponse.send).toHaveBeenCalledWith({ id: 'i', email: 'e' }); + expect(fakeResponse.redirect).toHaveBeenCalledWith( + '/error?code=unverified_user&provider=custom' + ); + expect(next).not.toHaveBeenCalled(); }); }); diff --git a/test/server/middleware/auth/platform.test.js b/test/server/middleware/auth/platform.test.js index 6c960220..e6a76127 100644 --- a/test/server/middleware/auth/platform.test.js +++ b/test/server/middleware/auth/platform.test.js @@ -59,7 +59,8 @@ describe('redirectUsingProviderMiddleware', () => { expect(getAuthRedirectUrl).toHaveBeenCalledWith( 'google', 'abc', - 'https://site.com/api/auth/callback/google' + 'https://site.com/api/auth/callback/google', + undefined ); expect(fakeResponse.redirect).toHaveBeenCalledWith('https://auth.url'); }); diff --git a/test/server/middleware/provider/getAll.test.js b/test/server/middleware/provider/getAll.test.js index ba230337..9c026235 100644 --- a/test/server/middleware/provider/getAll.test.js +++ b/test/server/middleware/provider/getAll.test.js @@ -25,7 +25,9 @@ describe('getAllProvidersMiddleware', () => { await getAllProvidersMiddleware(fakeRequest, fakeResponse); expect(fetchProviders).toHaveBeenCalled(); - expect(fakeResponse._getJSONData()).toEqual([{ provider: 'github' }]); + expect(fakeResponse._getJSONData()).toEqual([ + { provider: 'github', data: {} }, + ]); expect(handleError).not.toHaveBeenCalled(); });