> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kvelden.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SSO with Okta

> Step-by-step guide to connect Okta to Enclave for enterprise single sign-on, using either SAML 2.0 or OIDC — including the exact field mappings, SP certificate setup, and troubleshooting.

Connect your Okta org to Enclave so your workforce signs in with Okta. Enclave supports both **SAML 2.0** and **OIDC** with Okta — pick one. See the [Authentication overview](/organization/authentication) for how SSO fits with the rest of Enclave.

<Info>
  **Where:** **Organization → Single Sign-On** in Enclave. Only the **Owner** role can manage SSO connections. One email domain maps to one connection.
</Info>

## Before you start

1. You need **Owner** access in Enclave and **admin** access in Okta.
2. Decide **SAML** or **OIDC** — both work. OIDC is a little simpler (no SP certificate); SAML is the traditional enterprise choice. The rest of this page has a section for each.
3. Have your **email domain** ready (e.g. `acme.com`) — you'll verify ownership of it.

***

## Option A — OIDC (recommended for simplicity)

<Steps>
  <Step title="Create an OIDC app in Okta">
    Okta Admin → **Applications → Create App Integration** → **OIDC - OpenID Connect** → **Web Application**.

    * **Sign-in redirect URI:** `https://<your-enclave-host>/api/auth/oidc/callback`
    * **Grant type:** Authorization Code
    * Assign the app to the users/groups who should have access.

    Copy the **Client ID** and **Client Secret**.
  </Step>

  <Step title="Add the connection in Enclave">
    **Organization → Single Sign-On → Add Connection → OIDC**:

    | Field                     | Value                                                                              |
    | ------------------------- | ---------------------------------------------------------------------------------- |
    | Domain                    | your email domain (e.g. `acme.com`)                                                |
    | Issuer URL                | `https://<your-okta-domain>.okta.com` (e.g. `https://integrator-5434769.okta.com`) |
    | Client ID / Client Secret | from the previous step                                                             |

    Enclave discovers the endpoints automatically. The client secret is encrypted at rest with your KMS.
  </Step>

  <Step title="Verify your domain, then enable">
    Complete [domain verification](#verify-your-domain) below, toggle the connection **Enabled**, and sign in with an email on the domain.
  </Step>
</Steps>

***

## Option B — SAML 2.0

Okta's "View SAML setup instructions" screen gives you several values — the trick is knowing which goes where. **A URL is not always an ID.**

<Steps>
  <Step title="Create a SAML app in Okta">
    Okta Admin → **Applications → Create App Integration** → **SAML 2.0**. On the **Configure SAML** step:

    | Okta field                                     | Value                                                                                                                                 |
    | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
    | Single sign-on URL                             | `https://<your-enclave-host>/api/auth/saml/acs`                                                                                       |
    | Use this for Recipient URL and Destination URL | ✅ checked                                                                                                                             |
    | Audience URI (SP Entity ID)                    | your connection's **per-connection metadata URL** — see step 3 (`https://<your-enclave-host>/api/auth/saml/metadata/<connection-id>`) |
    | Name ID format                                 | `EmailAddress`                                                                                                                        |
    | Application username                           | `Email`                                                                                                                               |

    Under **Attribute Statements**, map at least **email** (first/last name are picked up automatically). Finish the wizard.
  </Step>

  <Step title="Set signing options (must match)">
    In the app's **SAML Settings → Show Advanced Settings**, confirm:

    * **Response** or **Assertion Signature** → **Signed** (assertion-signed is fine)
    * **Signature Algorithm** → **RSA-SHA256**
    * **Digest Algorithm** → **SHA256**
    * **Assertion Encryption** → **Unencrypted** (Enclave does not support encrypted assertions)
  </Step>

  <Step title="Add the connection in Enclave — map the fields carefully">
    **Organization → Single Sign-On → Add Connection → SAML.** Get the IdP values from Okta's app **Sign On → View SAML setup instructions**:

    | Okta value (from "View SAML setup instructions")          | Enclave field                                                               |
    | --------------------------------------------------------- | --------------------------------------------------------------------------- |
    | **Identity Provider Single Sign-On URL** (`…/sso/saml`)   | **SSO URL**                                                                 |
    | **Identity Provider Issuer** (`http://www.okta.com/exk…`) | **IdP Entity ID / Issuer**                                                  |
    | **X.509 Certificate**                                     | **X.509 Certificate**                                                       |
    | *Identity Provider metadata* (`…/sso/saml/metadata`)      | **not used** — this is only the *location* of the config, not a field value |

    <Warning>
      The **IdP Entity ID / Issuer** is Okta's **Identity Provider Issuer**
      (`http://www.okta.com/exk15me6794se8pM1698`) — **not** the Okta metadata URL
      (`…/sso/saml/metadata`). If you paste the metadata URL here, sign-in fails with
      "assertion validation failed" (`idp_issuer_mismatch`). Tip: open the metadata
      URL in a browser and copy the `entityID="…"` value — *that* is the Issuer.
    </Warning>
  </Step>

  <Step title="Provision the SP signing certificate">
    Enclave signs SAML requests with its own **Service Provider certificate**. On the connection card, under **SP signing certificate**, click **Generate (self-signed)** — no OpenSSL needed. (You can also **Use internal CA** or **Upload** your own.) The private key is encrypted at rest with your KMS.
  </Step>

  <Step title="Set Okta's Audience to the per-connection metadata URL">
    On the connection card, copy the **SP Entity ID / Audience URI** (it equals the per-connection metadata URL, `…/api/auth/saml/metadata/<connection-id>`) and paste it into Okta's **Audience URI (SP Entity ID)** field.

    <Warning>
      Okta's Audience is Enclave's **per-connection** metadata URL (with the connection
      id) — not the bare `/api/auth/saml/metadata`. A mismatch fails with
      `audience_mismatch`.
    </Warning>
  </Step>

  <Step title="Verify your domain, then enable and test">
    Complete [domain verification](#verify-your-domain), toggle **Enabled**, and sign in with an email on the domain.
  </Step>
</Steps>

***

## Verify your domain

Before a connection can sign anyone in, prove you control its email domain (prevents domain squatting across tenants).

<Steps>
  <Step title="Copy the TXT record">
    The connection card shows a DNS **TXT** record like `enclave-verification=<token>`.
  </Step>

  <Step title="Publish it and verify">
    Add it at your domain's apex (e.g. `acme.com`) in your DNS provider, then click **Verify**. DNS can take a few minutes to propagate.
  </Step>
</Steps>

<Note>
  A connection will not route or complete any sign-in until its domain is verified — even if toggled on.
</Note>

***

## After it works — per-connection policies

On the connection card you can tune, at any time:

* **Who can sign in (provisioning mode):** *Invited users only* (default — unknown Okta identities are rejected) or *Anyone in the directory* (auto-provision).
* **Require fresh sign-in at IdP:** force Okta to re-authenticate on every login.
* **Single Logout (SLO):** also end the Okta session when the user signs out of Enclave (turn on Okta's SLO too).

See [Authentication](/organization/authentication) for the full behavior of each.

***

## Troubleshooting

The ACS response and server logs name the exact cause. Common `reason` values:

| Reason                  | Fix                                                                                                                      |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `idp_issuer_mismatch`   | **IdP Entity ID / Issuer** must be Okta's *Identity Provider Issuer* (`http://www.okta.com/exk…`), not the metadata URL. |
| `audience_mismatch`     | Okta's **Audience URI** must equal the connection's per-connection metadata URL (with the id).                           |
| `destination_mismatch`  | Okta's **Single sign-on URL** must equal `…/api/auth/saml/acs`.                                                          |
| `signature_invalid`     | The **X.509 Certificate** in the connection must be Okta's current signing cert; algorithms must be RSA-SHA256 / SHA256. |
| `assertion_not_signed`  | Set **Assertion (or Response) Signature → Signed** in Okta.                                                              |
| `timing_or_clock_skew`  | The assertion is outside its validity window — check the server clock (NTP).                                             |
| `inresponseto_mismatch` | Start sign-in from **Enclave** (SP-initiated), not the Okta dashboard tile.                                              |

If you still see "invalid or expired SSO session", start the login from Enclave's sign-in page (not the Okta app tile) — Enclave is SP-initiated only.
