{"record":{"id":"66d8743ee3188a82","repo":"decolua/9router","slug":"idp-x-509-certificate-samlcert-is-missing-or-not","errorCode":null,"errorMessage":"IdP X.509 Certificate (samlCert) is missing or not configured","messagePattern":"IdP X\\.509 Certificate \\(samlCert\\) is missing or not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/lib/auth/saml.js","lineNumber":135,"sourceCode":"  const match = xml.match(/ID=\"([^\"]+)\"/);\n  const requestId = match ? match[1] : \"\";\n\n  const authorizeUrl = await samlInstance._requestToUrlAsync(xml, null, \"authorize\", {});\n\n  return { authorizeUrl, requestId };\n}\n\n/**\n * Validates SAML POST response from IdP ACS callback and returns user profile.\n * @param {Request} request\n * @param {object} body - Parsed form body or object containing SAMLResponse\n * @param {string} expectedRequestId - Request ID stored in saml_state cookie\n * @param {object} settings\n * @returns {Promise<object>}\n */\nexport async function validateSamlResponse(request, body, expectedRequestId, settings) {\n  if (!settings?.samlCert) {\n    throw new Error(\"IdP X.509 Certificate (samlCert) is missing or not configured\");\n  }\n\n  const origin = getSamlBaseUrl(request, settings);\n  const samlInstance = createSamlInstance(settings, origin);\n\n  const container = typeof body === \"object\" && body !== null ? body : { SAMLResponse: body };\n  const rawSamlResponse = container.SAMLResponse;\n\n  if (!rawSamlResponse) {\n    throw new Error(\"Missing SAMLResponse parameter in assertion POST body\");\n  }\n\n  // Parse response XML to inspect InResponseTo for replay protection\n  if (expectedRequestId) {\n    const xml = Buffer.from(rawSamlResponse, \"base64\").toString(\"utf8\");\n    const match = xml.match(/InResponseTo=[\"']([^\"']+)[\"']/i);\n    const inResponseTo = match ? match[1] : null;\n","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/lib/auth/saml.js#L117-L153","documentation":"validateSamlResponse refuses to process a SAML POST assertion until an IdP X.509 certificate has been configured in settings (settings.samlCert). The certificate is required to construct the @node-saml instance and to verify the digital signature of the SAMLResponse; without it, assertions cannot be trusted. The check runs first, before any parsing or validation of the response body.","triggerScenarios":"Calling validateSamlResponse(request, body, expectedRequestId, settings) where settings is null/undefined, settings.samlCert is undefined, an empty string, or whitespace (falsy).","commonSituations":"Admin enabled SAML login but never pasted the IdP's certificate into settings; the certificate field was saved to the wrong settings key; settings were imported/migrated and samlCert was dropped; a fresh environment was provisioned without completing IdP metadata setup; the certificate was rotated and the new cert removed rather than replacing the old one.","solutions":["Open the dashboard SAML settings and paste the IdP's X.509 certificate (PEM, base64 body) into the samlCert field, then save.","Export the certificate from your IdP (e.g. Okta/Entra 'Signing certificate', ADFS token-signing cert) and verify it matches the IdP currently issuing assertions.","If settings come from an import/sync, re-run the import and confirm samlCert is present in the payload before retrying the login.","Log/inspect the settings object passed to validateSamlResponse to confirm the key is named exactly samlCert and is non-empty."],"exampleFix":"// before\nawait validateSamlResponse(req, req.body, stateId, settings); // settings.samlCert === undefined\n// after\nif (!settings?.samlCert) throw new Error('Configure IdP X.509 certificate (samlCert) in settings first');\nawait validateSamlResponse(req, req.body, stateId, settings);","handlingStrategy":"validation","validationCode":"function isSamlConfigReady(settings) {\n  return typeof settings?.samlCert === 'string' && settings.samlCert.trim().length > 0;\n}\n// call: if (!isSamlConfigReady(settings)) redirect to SSO setup instead of invoking validateSamlResponse","typeGuard":"function hasSamlCert(s) {\n  return !!s && typeof s === 'object' && typeof s.samlCert === 'string' && s.samlCert.trim() !== '';\n}","tryCatchPattern":"try {\n  const profile = await validateSamlResponse(req, body, stateId, settings);\n} catch (err) {\n  if (String(err.message).includes('samlCert')) {\n    return res.status(503).json({ error: 'SAML not configured', hint: 'Set the IdP X.509 certificate in settings' });\n  }\n  throw err;\n}","preventionTips":["Validate SAML settings (cert present, well-formed PEM) at save time in the admin UI, not only at login time.","Add a startup/health check that warns when SAML is enabled but samlCert is empty.","After IdP certificate rotation, update samlCert and re-test login; keep the old cert temporarily if the IdP supports dual signing certs.","Store settings via a single schema-validated path so imports/syncs cannot silently drop the samlCert key."],"tags":["saml","sso","configuration","auth"],"backgroundTag":"missing-saml-certificate","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}