{"record":{"id":"0cf5645bb5305cfe","repo":"Budibase/budibase","slug":"recaptcha-token-not-found","errorCode":null,"errorMessage":"Recaptcha token not found","messagePattern":"Recaptcha token not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/server/src/api/controllers/recaptcha.ts","lineNumber":21,"sourceCode":"  VerifyRecaptchaRequest,\n  VerifyRecaptchaResponse,\n  CheckRecaptchaResponse,\n  RecaptchaSessionCookie,\n} from \"@budibase/types\"\nimport { utils, Cookie, configs, UnexpectedError } from \"@budibase/backend-core\"\nimport {\n  setRecaptchaVerified,\n  isRecaptchaVerified,\n} from \"../../utilities/redis\"\nimport fetch from \"node-fetch\"\n\nexport async function verify(\n  ctx: Ctx<VerifyRecaptchaRequest, VerifyRecaptchaResponse>\n) {\n  const { token } = ctx.request.body\n\n  if (!token) {\n    throw new Error(\"Recaptcha token not found\")\n  }\n\n  const config = await configs.getRecaptchaConfig()\n  if (!config) {\n    throw new Error(\"No recaptcha config found\")\n  }\n\n  try {\n    const response = await fetch(\n      \"https://www.google.com/recaptcha/api/siteverify\",\n      {\n        method: \"POST\",\n        headers: {\n          \"Content-Type\": \"application/x-www-form-urlencoded\",\n        },\n        body: new URLSearchParams({\n          secret: config.config.secretKey,\n          response: token,","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/recaptcha.ts#L3-L39","documentation":"The recaptcha `verify` controller reads `token` from the request body and throws immediately if it is missing or falsy. The endpoint requires the client to supply the reCAPTCHA token obtained from the widget before server-side verification against Google can happen.","triggerScenarios":"POSTing to the recaptcha verify endpoint with an empty body, `token: undefined/null/\"\"`, or a request where the client-side widget never produced a token (script blocked, widget not rendered).","commonSituations":"Frontend forgot to call `grecaptcha.getResponse()`; ad blockers or CSP blocking the reCAPTCHA script so no token is generated; form field name mismatch (sending `captcha` or `recaptchaResponse` instead of `token`); API consumers calling the endpoint manually without the field.","solutions":["Include the reCAPTCHA token in the request body under the `token` key: `{ token: grecaptcha.getResponse() }`","Fix the client to render the reCAPTCHA widget and capture its token before submitting","Check the field name matches `token` exactly","Verify the widget actually executed (user completed the challenge) before sending"],"exampleFix":"// before\nawait api.post(\"/api/recaptcha/verify\", { captcha: resp })\n// after\nconst token = grecaptcha.getResponse()\nif (!token) return\nawait api.post(\"/api/recaptcha/verify\", { token })","handlingStrategy":"validation","validationCode":"if (!body.token || typeof body.token !== \"string\") {\n  throw new Error(\"Client must supply a recaptcha token before verifying\")\n}","typeGuard":"const hasRecaptchaToken = (b) =>\n  typeof b === \"object\" && b !== null && \"token\" in b && typeof b.token === \"string\" && b.token.length > 0","tryCatchPattern":"try {\n  await verifyRecaptcha({ token })\n} catch (e) {\n  if (String(e.message).includes(\"Recaptcha token not found\")) {\n    // re-render widget / ask user to complete the challenge\n  }\n}","preventionTips":["Always check `grecaptcha.getResponse()` is non-empty before calling verify","Keep client and server field names consistent (`token`)","Handle environments where the reCAPTCHA script fails to load","Add client-side validation before form submission"],"tags":["recaptcha","validation","missing-field"],"backgroundTag":"missing-required-field","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}