decolua/9router · error

IdP X.509 Certificate (samlCert) is missing or not configure

Error message

IdP X.509 Certificate (samlCert) is missing or not configured

What it means

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.

Source

Thrown at src/lib/auth/saml.js:135

  const match = xml.match(/ID="([^"]+)"/);
  const requestId = match ? match[1] : "";

  const authorizeUrl = await samlInstance._requestToUrlAsync(xml, null, "authorize", {});

  return { authorizeUrl, requestId };
}

/**
 * Validates SAML POST response from IdP ACS callback and returns user profile.
 * @param {Request} request
 * @param {object} body - Parsed form body or object containing SAMLResponse
 * @param {string} expectedRequestId - Request ID stored in saml_state cookie
 * @param {object} settings
 * @returns {Promise<object>}
 */
export async function validateSamlResponse(request, body, expectedRequestId, settings) {
  if (!settings?.samlCert) {
    throw new Error("IdP X.509 Certificate (samlCert) is missing or not configured");
  }

  const origin = getSamlBaseUrl(request, settings);
  const samlInstance = createSamlInstance(settings, origin);

  const container = typeof body === "object" && body !== null ? body : { SAMLResponse: body };
  const rawSamlResponse = container.SAMLResponse;

  if (!rawSamlResponse) {
    throw new Error("Missing SAMLResponse parameter in assertion POST body");
  }

  // Parse response XML to inspect InResponseTo for replay protection
  if (expectedRequestId) {
    const xml = Buffer.from(rawSamlResponse, "base64").toString("utf8");
    const match = xml.match(/InResponseTo=["']([^"']+)["']/i);
    const inResponseTo = match ? match[1] : null;

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Open the dashboard SAML settings and paste the IdP's X.509 certificate (PEM, base64 body) into the samlCert field, then save.
  2. 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.
  3. If settings come from an import/sync, re-run the import and confirm samlCert is present in the payload before retrying the login.
  4. Log/inspect the settings object passed to validateSamlResponse to confirm the key is named exactly samlCert and is non-empty.

Example fix

// before
await validateSamlResponse(req, req.body, stateId, settings); // settings.samlCert === undefined
// after
if (!settings?.samlCert) throw new Error('Configure IdP X.509 certificate (samlCert) in settings first');
await validateSamlResponse(req, req.body, stateId, settings);
Defensive patterns

Strategy: validation

Validate before calling

function isSamlConfigReady(settings) {
  return typeof settings?.samlCert === 'string' && settings.samlCert.trim().length > 0;
}
// call: if (!isSamlConfigReady(settings)) redirect to SSO setup instead of invoking validateSamlResponse

Type guard

function hasSamlCert(s) {
  return !!s && typeof s === 'object' && typeof s.samlCert === 'string' && s.samlCert.trim() !== '';
}

Try / catch

try {
  const profile = await validateSamlResponse(req, body, stateId, settings);
} catch (err) {
  if (String(err.message).includes('samlCert')) {
    return res.status(503).json({ error: 'SAML not configured', hint: 'Set the IdP X.509 certificate in settings' });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling validateSamlResponse(request, body, expectedRequestId, settings) where settings is null/undefined, settings.samlCert is undefined, an empty string, or whitespace (falsy).

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/66d8743ee3188a82. Report an issue: GitHub.