From c18726d712dd2988a60fcc15e17d179c8253e671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Mon, 9 Feb 2026 16:20:41 +0100 Subject: [PATCH] Fix captcha validation failing due to missing URL in secure axios adapter (#17807) ## Summary - Fixes login failing with `Error: URL is required` when captcha (Google reCAPTCHA or Turnstile) is enabled - The secure axios adapter (`getSecureAxiosAdapter`) checked `config.url` before `baseURL` resolution. In Axios, `baseURL + url` combination happens inside the default HTTP adapter, not before custom adapters are called. When captcha drivers configure a `baseURL` and call `.post('', data)`, the empty string url was incorrectly treated as missing. - The adapter now resolves `baseURL` + `url` itself before validation, matching the default Axios HTTP adapter behavior ## Test plan - [x] Existing unit tests (23 tests) all pass - [ ] Verify login works with captcha enabled (`CAPTCHA_DRIVER` set to `google-recaptcha` or `turnstile`) Made with [Cursor](https://cursor.com) Co-authored-by: Cursor --- .../tool/utils/get-secure-axios-adapter.util.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/tool/utils/get-secure-axios-adapter.util.ts b/packages/twenty-server/src/engine/core-modules/tool/utils/get-secure-axios-adapter.util.ts index fff182d85a..085c562914 100644 --- a/packages/twenty-server/src/engine/core-modules/tool/utils/get-secure-axios-adapter.util.ts +++ b/packages/twenty-server/src/engine/core-modules/tool/utils/get-secure-axios-adapter.util.ts @@ -23,11 +23,21 @@ export const getSecureAxiosAdapter = ( const { dnsLookup, httpAdapter } = dependencies; return async (config: InternalAxiosRequestConfig) => { - if (!config.url) { + // Resolve full URL by combining baseURL and url, matching what the + // default axios HTTP adapter does internally. Without this, requests + // that rely on baseURL (e.g. captcha drivers) would fail the check + // below because config.url can be an empty string. + const resolvedUrl = config.url + ? config.baseURL + ? new URL(config.url, config.baseURL).toString() + : config.url + : config.baseURL; + + if (!resolvedUrl) { throw new Error('URL is required'); } - const url = new URL(config.url); + const url = new URL(resolvedUrl); if (!['http:', 'https:'].includes(url.protocol)) { throw new Error('URL should use http/https protocol');