{"record":{"id":"e9cf26dce4f46bda","repo":"Budibase/budibase","slug":"license-does-not-allow-oidc-pkce-method-support","errorCode":null,"errorMessage":"License does not allow OIDC PKCE method support","messagePattern":"License does not allow OIDC PKCE method support","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/worker/src/api/controllers/global/configs.ts","lineNumber":247,"sourceCode":"}\n\nasync function processGoogleConfig(\n  config: GoogleInnerConfig,\n  existing?: GoogleInnerConfig\n) {\n  await verifySSOConfig(ConfigType.GOOGLE, config)\n\n  if (existing && config.clientSecret === PASSWORD_REPLACEMENT) {\n    config.clientSecret = existing.clientSecret\n  }\n}\n\nasync function processOIDCConfig(config: OIDCConfigs, existing?: OIDCConfigs) {\n  await verifySSOConfig(ConfigType.OIDC, config.configs[0])\n\n  const anyPkceSettings = config.configs.find(cfg => cfg.pkce)\n  if (anyPkceSettings && !(await pro.features.isPkceOidcEnabled())) {\n    throw new Error(\"License does not allow OIDC PKCE method support\")\n  }\n\n  config.configs.filter(c => c.pkce === null).forEach(c => delete c.pkce)\n\n  if (existing) {\n    for (const c of config.configs) {\n      const existingConfig = existing.configs.find(e => e.uuid === c.uuid)\n      if (!existingConfig) {\n        continue\n      }\n      if (c.clientSecret === PASSWORD_REPLACEMENT) {\n        c.clientSecret = existingConfig.clientSecret\n      }\n    }\n  }\n}\n\nexport async function processRecaptchaConfig(","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/worker/src/api/controllers/global/configs.ts#L229-L265","documentation":"processOIDCConfig validates the OIDC config on save. If any OIDC config entry sets pkce but the tenant license does not include the PKCE-for-OIDC feature (pro.features.isPkceOidcEnabled()), the save fails. PKCE is a paid/license-gated capability.","triggerScenarios":"Saving an OIDC config where any entry in config.configs has pkce set truthy while the license lacks the OIDC PKCE feature.","commonSituations":"Users on free/lower-tier licenses copying a config template that includes pkce:true, or UI exposing a PKCE toggle that should be hidden by entitlement; license key not upgraded or not refreshed.","solutions":["Remove the pkce field (or set it false) from the OIDC config entries","Upgrade the license to a plan that includes OIDC PKCE support","Re-sync/refresh the license key so entitlements update","Confirm which config entry carries pkce via the API and strip it server-side before save"],"exampleFix":"// before\n{ \"configs\": [{ \"clientId\": \"x\", \"pkce\": true }] }\n// after\n{ \"configs\": [{ \"clientId\": \"x\" }] } // or upgrade license for pkce: true","handlingStrategy":"validation","validationCode":"import { features } from \"@budibase/pro\"\n// client-side equivalent: check entitlements from the org/license info endpoint\nconst pkceAllowed = await pro.features.isPkceOidcEnabled()\nconst payload = configs.map(c => pkceAllowed ? c : { ...c, pkce: undefined })","typeGuard":null,"tryCatchPattern":"try {\n  await configApi.save(oidcConfig)\n} catch (err) {\n  if (err.message.includes(\"OIDC PKCE\")) {\n    // strip pkce and retry, or prompt for license upgrade\n  } else { throw err }\n}","preventionTips":["Hide PKCE options in UI when the entitlement is absent","Fetch feature entitlements before rendering license-gated settings","Strip license-gated fields from copied config templates","Verify license validity before editing premium auth settings"],"tags":["oidc","pkce","licensing","entitlements"],"backgroundTag":"license-feature-gated","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}