1Panel-dev/1Panel · error · Error

Invalid SAML2 navigation response

Error message

Invalid SAML2 navigation response

What it means

submitSAML2Navigation (frontend/src/utils/saml2.ts:26) throws when the navigation object is neither a valid redirect (binding 'redirect' with redirectURL) nor a valid post (binding 'post' with postURL and fields). This guards against malformed backend responses before any DOM form is built; it indicates the SAML2 backend produced a navigation payload missing required keys, not a user input error.

Source

Thrown at frontend/src/utils/saml2.ts:26

          postURL: string;
          fields: Record<string, string>;
      };

const validateNavigationURL = (value: string) => {
    const url = new URL(value, window.location.origin);
    if (!['http:', 'https:'].includes(url.protocol)) {
        throw new Error('Unsupported SAML2 navigation protocol');
    }
    return url.toString();
};

export const submitSAML2Navigation = (navigation: SAML2Navigation, targetWindow: Window = window) => {
    if (navigation.binding === 'redirect' && navigation.redirectURL) {
        targetWindow.location.assign(validateNavigationURL(navigation.redirectURL));
        return;
    }
    if (navigation.binding !== 'post' || !navigation.postURL || !navigation.fields) {
        throw new Error('Invalid SAML2 navigation response');
    }

    const form = targetWindow.document.createElement('form');
    form.method = 'POST';
    form.action = validateNavigationURL(navigation.postURL);
    form.style.display = 'none';

    Object.entries(navigation.fields || {}).forEach(([name, value]) => {
        const input = targetWindow.document.createElement('input');
        input.type = 'hidden';
        input.name = name;
        input.value = value;
        form.appendChild(input);
    });

    targetWindow.document.body.appendChild(form);
    form.submit();
    form.remove();

View on GitHub (pinned to 5ac7c80881)

Solutions

  1. Log/inspect the navigation object received from the backend (devtools network tab on the SAML2 endpoint)
  2. Verify the backend serializes {binding:'redirect',redirectURL} or {binding:'post',postURL,fields} exactly — empty strings and undefined both trigger it
  3. Check for frontend/backend version mismatch after a partial upgrade of the panel

Example fix

// backend payload before
{ binding: 'post', postURL: 'https://idp/sso', fields: {} } // throws
// after
{ binding: 'post', postURL: 'https://idp/sso', fields: { SAMLRequest: '...' } }
Defensive patterns

Strategy: type-guard

Validate before calling

const hasRedirect = (n: SAML2Navigation) => n.binding === 'redirect' && Boolean(n.redirectURL);
const hasPost = (n: SAML2Navigation) => n.binding === 'post' && Boolean(n.postURL) && Boolean(n.fields) && Object.keys(n.fields).length > 0;

Type guard

const isSAML2Navigation = (v: unknown): v is SAML2Navigation => {
    if (typeof v !== 'object' || v === null) return false;
    const n = v as Record<string, unknown>;
    if (n.binding === 'redirect') return typeof n.redirectURL === 'string' && n.redirectURL.length > 0;
    if (n.binding === 'post') return typeof n.postURL === 'string' && n.postURL.length > 0
        && typeof n.fields === 'object' && n.fields !== null && Object.keys(n.fields).length > 0;
    return false;
};

Try / catch

if (!isSAML2Navigation(payload)) { throw new Error('Malformed SAML2 navigation from server — check panel/IdP version match'); }
submitSAML2Navigation(payload);

Prevention

When it happens

Trigger: Backend returns binding 'post' with an empty fields object; postURL missing/empty; binding value other than 'redirect'/'post'; redirect binding with an empty redirectURL falls through to this check.

Common situations: SAML2 login response truncated or version-skewed between frontend expectations and backend DTO; backend error payload mistaken for a navigation payload; IdP returning a binding the panel does not support.

Related errors


AI-assisted analysis of 1Panel-dev/1Panel@5ac7c80881 (2026-08-15). Data as JSON: /api/errors/8e544c1bee7ea198. Report an issue: GitHub.