SAML with Okta — Metadata not persisting in n8n Business Edition (Helm deployment)

I’m setting up SAML authentication with Okta for n8n Business Edition (self-hosted on Kubernetes using Helm) and facing some issues.

When I try to log in via Okta, I get this error:

{"code":401,"message":"SAML Authentication failed: SAML Authentication failed. Could not parse SAML response. ERR_IDP_METADATA_MISSING_SINGLE_SIGN_ON_SERVICE"}

Here’s what I’ve tried:

  1. Initially, I set the environment variable:

    N8N_SAML_METADATA_URL=https://org.okta.com/app/**********58/sso/saml/metadata
    But the metadata URL did not appear in the IdP metadata field in the n8n admin UI.
    
  2. Then, I created a ConfigMap with the downloaded Okta metadata XML and mounted it in my deployment:

    N8N_SAML_METADATA_PATH=/home/node/.n8n/public/static/okta-metadata.xml
    
    

    I can see the XML file inside the pod, but the IdP metadata field in n8n UI is still blank.

  3. If I manually upload the metadata XML or URL in the n8n UI, SSO works — but whenever I redeploy or update my Helm release, that field resets to blank, and I get the same error again.

I’ve also set the following environment variables:

N8N_SAML_LOGIN_ENABLED=true
N8N_SAML_METADATA_PATH=/home/node/.n8n/public/static/okta-metadata.xml (when using Metadata XML)
N8N_SAML_METADATA_URL="https://url" (when using metadata URL)

Could you please let me know how to persist the IdP metadata (URL or XML) via Helm configuration, so it survives redeployments and works automatically with Okta?

Reference documentation : Okta Workforce Identity SAML setup | n8n Docs

alright, i see what’s happening here. this is a pretty common helm/kubernetes issue with n8n saml - the metadata isn’t persisting because the config is being stored in the database, not just reading from env vars on startup.

here’s the deal:

**the root problem:** n8n reads saml metadata once during initial setup and stores it in the database. when you redeploy, the database persists but the env vars get ignored for already-configured saml settings. the UI field is blank because it’s trying to reference metadata that wasn’t properly loaded the first time.

**what actually works:**

1. **don’t use `N8N_SAML_METADATA_PATH` or `N8N_SAML_METADATA_URL`** - these only work on first-time setup, not for updates

2. **instead, use `N8N_SAML_METADATA` with the raw XML** directly in your helm values:

```yaml

env:

  • name: N8N_SAML_LOGIN_ENABLED

    value: “true”

  • name: N8N_SAML_METADATA

    valueFrom:

    configMapKeyRef:

    name: saml-metadata
    
    key: metadata.xml
    

```

then create a configmap with your okta metadata:

```yaml

apiVersion: v1

kind: ConfigMap

metadata:

name: saml-metadata

data:

metadata.xml: |

<?xml version="1.0" encoding="UTF-8"?>

<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="...">

  <!-- your full okta metadata xml here -->

</EntityDescriptor>

```

3. **clear the database before deploying with this config** - if saml is already partially configured in your db, you need to reset it:

```bash

# scale down the deployment

kubectl scale deployment n8n -n your-namespace --replicas=0

# connect to postgres and run:

DELETE FROM settings WHERE key = ‘saml’;

# scale back up

kubectl scale deployment n8n -n your-namespace --replicas=1

```

or if you’re using a fresh database, just apply the env vars and it should work on first startup.

4. **other settings you probably need** in your helm values too:

```yaml

env:

  • name: N8N_SAML_LOGIN_ENABLED

    value: “true”

  • name: N8N_SAML_LOGIN_BUTTON_LABEL

    value: “Login with Okta”

  • name: N8N_SAML_LOGIN_LABEL

    value: “Organization”

  • name: N8N_SAML_METADATA

    valueFrom:

    configMapKeyRef:

    name: saml-metadata
    
    key: metadata.xml
    

```

**after the redeploy**, you should see the IdP metadata populated in the admin UI and your okta sso should work persistently.

the key thing is - stop trying to make n8n read from a file path. pass the actual xml content via env var (through a configmap) and make sure the db is clean before first deploy.

lmk if you hit any issues with this approach - the docs on this are kinda sparse tbh