> ## 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.

# Authentication

> How users sign in to Enclave — local accounts, enterprise SSO (OIDC and SAML 2.0), LDAP / Active Directory, and external guest verification — with configuration steps for each.

## Supported authentication methods

| Method                          | Protocol                                         | Who it's for                           | Availability              |
| ------------------------------- | ------------------------------------------------ | -------------------------------------- | ------------------------- |
| **Local accounts**              | Email + password                                 | Any user; the default                  | All deployments           |
| **Enterprise SSO — OIDC**       | OpenID Connect                                   | Workforce sign-in via your IdP         | All deployments           |
| **Enterprise SSO — SAML**       | SAML 2.0                                         | Workforce sign-in via your IdP         | All deployments           |
| **LDAP / Active Directory**     | LDAP(S) bind                                     | Directory-backed sign-in               | Private Virtual Appliance |
| **External guest verification** | Email OTP, Google / Microsoft OAuth, or your IdP | Counterparties invited to secure rooms | All deployments           |

<Info>
  Methods are not mutually exclusive. A user invited with a local password can later sign in through SSO once their email domain is connected — the same account is used, and both methods keep working.
</Info>

## How sign-in routing works

Enclave routes each sign-in attempt by the identifier the user enters:

* **Email address with an SSO-connected domain** → redirected to that domain's IdP (OIDC or SAML). One email domain maps to exactly one organization.
* **`connection\username`** (appliance only) → authenticated against the configured LDAP / Active Directory connection.
* **Anything else** → local email + password.

Sessions are issued as signed JWTs regardless of method. Changing a user's password or role immediately invalidates all previously issued sessions for that user.

***

## Local accounts

Local accounts are created by an Owner or Admin inviting a user, and authenticate with email + password. Passwords are stored only as bcrypt hashes.

* Users provisioned just-in-time by SSO or LDAP receive an unusable random password — they authenticate at the IdP or directory.
* A user with a real local password keeps it even after SSO is enabled for their domain; both sign-in paths work.
* Changing the password revokes every session issued before the change.

***

## Enterprise SSO

Enterprise SSO connects an **email domain** to your identity provider. Anyone signing in with an email on that domain is sent to your IdP; on success they are signed in — and provisioned automatically on first login.

**Where:** **Organization → Single Sign-On**. Only the **Owner** role can manage SSO connections.

**Provider-specific guides** (step-by-step field mappings): [Okta](/organization/sso/okta) · [Microsoft Entra ID](/organization/sso/entra-id) · [Google Workspace](/organization/sso/google-workspace) · [Custom (any OIDC/SAML IdP)](/organization/sso/custom). The sections below cover the concepts shared by all of them.

### Setup at a glance

1. **Register an application at your IdP** using the Service Provider URLs shown in the connection wizard (redirect URI for OIDC; ACS URL and SP Entity ID for SAML).
2. **Add the connection in Enclave** with your IdP's details — protocol-specific steps below.
3. **Verify your domain** with the DNS TXT challenge (required before the connection can sign anyone in).
4. **For SAML:** generate the SP signing certificate (one click) and import its metadata at your IdP.
5. **Enable the connection** — users whose email is on the configured domain are now routed to your IdP at sign-in.
6. **Test end-to-end** by signing in with a domain-matched email.

Each connection also exposes per-connection policies you can tune anytime from its card: **provisioning mode** (who may sign in), **Require fresh sign-in at IdP**, and **Single Logout**. These are covered below.

### Who can sign in (provisioning mode)

Authentication and authorization are separate: your IdP proves *who* someone is, but **who is allowed an Enclave account** is your decision. Each connection has a **provisioning mode**:

* **Invited users only** *(default, recommended)* — only people who already have an Enclave account (invited or previously provisioned) can sign in. An IdP identity with no matching account is **rejected**, not created. Membership stays under admin control instead of granting your whole directory access.
* **Anyone in the directory (auto-provision)** — the first successful IdP login automatically creates a **Member**. Opt in only if you intend everyone your IdP authenticates on this domain to have access.

Existing connections default to **invited users only**; this never locks out anyone who already has an account — it only stops new, un-invited identities from self-provisioning.

### How account matching works (JIT)

1. On first successful IdP login, Enclave matches the IdP's **stable subject** (OIDC `sub` / SAML NameID) to an existing linked account.
2. If no link exists yet, it matches by **email within your organization** (covering users who were invited before SSO) and records the subject link for next time.
3. If no account matches: in **auto** mode one is created as a **Member** in your root org unit; in **invited users only** mode the sign-in is refused with a message to contact an administrator.

Because identity is linked by the IdP's stable subject, a later email change at the IdP updates the existing account rather than creating a duplicate. Display names are kept in sync from the IdP on every login. Deprovisioning is manual — disabling a user at the IdP blocks new logins, and an admin removes the Enclave account.

### Verify your domain

Before a connection can sign anyone in, you must prove you control its email domain — this prevents another organization from claiming a domain that isn't theirs.

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

  <Step title="Publish it at your domain">
    Add that TXT record at your domain's apex (e.g. `acme.com`) in your DNS provider.
  </Step>

  <Step title="Verify">
    Click **Verify**. Once the record is found, the connection becomes active. DNS changes can take a few minutes to propagate. Re-pointing a connection to a new domain requires re-verification.
  </Step>
</Steps>

<Note>
  Until a connection's domain is verified, it will not route or complete any sign-in — even if it is toggled on.
</Note>

### Configure OIDC

Works with any OpenID Connect–compliant provider. Quick-pick templates are offered for Google, Microsoft (Entra ID), and Okta; **Custom** accepts any compliant issuer.

<Steps>
  <Step title="Create an application at your IdP">
    Register a **Web** application and set the redirect URI to:

    ```
    https://<your-enclave-host>/api/auth/oidc/callback
    ```

    Grant the standard scopes: `openid`, `profile`, `email`. Note the **Client ID** and **Client Secret**.
  </Step>

  <Step title="Add the connection in Enclave">
    Go to **Organization → Single Sign-On → Add Connection**, choose **OIDC**, and fill in:

    | Field                     | Value                                                                                                    |
    | ------------------------- | -------------------------------------------------------------------------------------------------------- |
    | Domain                    | Your email domain (e.g. `acme.com`)                                                                      |
    | Issuer URL                | Your IdP's issuer, e.g. `https://login.microsoftonline.com/{tenant}/v2.0` or `https://{domain}.okta.com` |
    | Client ID / Client Secret | From Step 1                                                                                              |

    Enclave discovers endpoints automatically from `{issuer}/.well-known/openid-configuration`. The client secret is encrypted at rest with the platform KMS.
  </Step>

  <Step title="Enable and test">
    Toggle the connection **Enabled**, then sign in with an email on the domain — you should be redirected to the IdP and back.
  </Step>
</Steps>

<Note>
  **Microsoft Entra ID:** if the ID token omits the standard `email` claim, Enclave falls back to `preferred_username` / `upn` automatically. For the cleanest setup, add `email` as an optional claim on the Entra app registration.
</Note>

### Configure SAML 2.0

Works with any SAML 2.0 IdP (Okta, Microsoft Entra ID, ADFS, PingFederate, and others).

<Steps>
  <Step title="Create a SAML application at your IdP">
    Configure your IdP with Enclave's Service Provider details. The exact values
    are shown on the connection card after you add it — the **Entity ID is
    per-connection** and equals the connection's metadata URL:

    | IdP setting                 | Value                                                                |
    | --------------------------- | -------------------------------------------------------------------- |
    | ACS URL (Reply URL)         | `https://<your-enclave-host>/api/auth/saml/acs`                      |
    | SP Entity ID / Audience URI | `https://<your-enclave-host>/api/auth/saml/metadata/<connection-id>` |
    | SP Metadata (import by URL) | the same per-connection URL as the Entity ID                         |

    <Warning>
      The **Entity ID / Audience URI is the per-connection metadata URL (with the
      connection id)** — not the bare `/api/auth/saml/metadata`. Copy it exactly
      from the connection card. Using the wrong value causes an "assertion
      validation failed" (audience mismatch) on sign-in.
    </Warning>

    Map at minimum an **email** attribute; first/last name are picked up automatically from the standard WS-\*, OID, or plain attribute names.
  </Step>

  <Step title="Add the connection in Enclave">
    Go to **Organization → Single Sign-On → Add Connection**, choose **SAML**, and fill in:

    | Field             | Value                                 |
    | ----------------- | ------------------------------------- |
    | Domain            | Your email domain                     |
    | IdP Entity ID     | From your IdP's metadata (`entityID`) |
    | SSO URL           | The IdP sign-in endpoint              |
    | X.509 Certificate | The IdP's PEM signing certificate(s)  |
    | NameID Format     | `Email address` (default) — see below |
  </Step>

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

  <Step title="Import the SP metadata at your IdP">
    Copy the per-connection **SP metadata** URL shown on the card
    (`/api/auth/saml/metadata/<id>`) and import it into your IdP so it trusts this
    connection's SP certificate.
  </Step>

  <Step title="Enable and test">
    Toggle the connection **Enabled** and sign in with an email on the domain.
  </Step>
</Steps>

<Note>
  **SP certificate.** A self-signed SP certificate is the SAML norm — IdPs trust it by
  exact match from the imported metadata, not by CA chain — so **Generate (self-signed)**
  is the recommended one-click default. If you rotate or regenerate it, **re-import the
  SP metadata at your IdP** before signing in again. If no per-connection certificate is
  set, Enclave falls back to the platform certificate (`SAML_CERT_PATH` / `SAML_KEY_PATH`).
</Note>

**NameID format.** Enclave requests `emailAddress` by default, which Okta and most IdPs accept. If your IdP rejects the request or returns errors about the NameID policy — common with Microsoft Entra and ADFS — switch the connection's NameID Format to **Persistent** or **Unspecified**.

**IdP signing-key rotation.** The certificate field accepts **multiple concatenated PEM certificates**. When your IdP announces a new signing certificate (Entra rotates keys periodically), paste the new certificate *alongside* the current one before the switch — assertions signed by either verify, so sign-in never breaks during the rollover.

### SSO security properties

* Every login is **SP-initiated** with a one-time, HMAC-signed state and a 10-minute window; IdP-initiated logins are rejected.
* SAML assertions are signature-verified against your configured certificate(s), with `InResponseTo` and validity-window checks. OIDC ID tokens are verified against the issuer's published keys with audience and nonce checks.
* OIDC client secrets are stored encrypted under the platform KMS.

### Security & access toggles (per connection)

Each connection has a **Security & access** panel on its card (no full re-edit needed) with two independent policies, both **off by default**:

* **Require fresh sign-in at IdP** — re-challenges the user at your IdP on *every* login, even when the IdP session is still live. Higher assurance and the reliable way to guarantee that a signed-out user cannot be silently re-authenticated; the trade-off is more frequent IdP prompts. Implemented as OIDC `prompt=login` / SAML `ForceAuthn`.
* **End IdP session on logout (Single Logout)** — see below.

These are complementary: *Require fresh sign-in* acts at **login** time (prove identity now); *Single Logout* acts at **logout** time (end the IdP session).

### Single Logout (SLO)

Off by default, per connection. When enabled, signing out of Enclave also ends the session at your IdP (OIDC RP-initiated logout / SAML `LogoutRequest`), so the user is fully signed out rather than silently re-authenticated on their next visit.

<Warning>
  SLO ends the **shared IdP session**, which may also sign the user out of other apps that use the same IdP. Enable it only if that is the behavior you want.
</Warning>

* Toggle it on the connection card under **Security & access** → **End IdP session on logout**.
* **IdP setup:** register Enclave's post-logout URL / import the SP metadata (which now advertises a SingleLogoutService at `/api/auth/saml/slo`). For OIDC, the IdP must publish an `end_session_endpoint`.
* **Direction:** SP-initiated only — signing out *of Enclave* ends the IdP session. Logging out *at the IdP* does not yet automatically end the Enclave session (that Enclave session still expires on its own short timer; use **Require fresh sign-in at IdP** for stricter behavior).
* **Best-effort by design:** local Enclave logout (cookie clear + token revocation) **always** happens first; if the IdP logout can't be completed (common with SAML front-channel SLO), your Enclave session is still ended — only the IdP session persists. The **Require fresh sign-in at IdP** toggle is the reliable backstop for that case.

### Session lifetime

* After sign-in, Enclave issues a short-lived session (default **90 minutes**, HttpOnly cookie). When it expires, SSO users are re-checked with the identity provider — **silently, with no password or MFA prompt, if the IdP session is still valid.** Effective re-auth cadence is therefore `min(Enclave session, your IdP session policy)`.
* **Sign-out is immediate and per-session:** logging out revokes *that* token right away (a captured copy cannot be replayed afterward) without affecting your other devices. Administrators disabling a user, or a password/role change, likewise revoke active sessions.
* Session length is operator-tunable via `AUTH_ACCESS_TOKEN_TTL` (15 minutes–24 hours).

### Current limitations

* **IdP-initiated logout** is not yet propagated — SP-initiated Single Logout (signing out *of Enclave*) is supported, but logging out *at the IdP* does not automatically end the Enclave session (it still expires on its own short timer).
* **SP certificate rotation is a hard cutover** — regenerating the SP certificate takes effect immediately, so re-import the SP metadata at your IdP before signing in again (no dual-certificate overlap window yet).
* **SAML metadata** must be entered field-by-field (no metadata-URL import yet).
* **Encrypted SAML assertions** are not supported — configure the IdP to sign, not encrypt.
* **No group-to-role mapping** — JIT users start as **Member**; assign roles in [Users](/organization/users).

***

## LDAP / Active Directory (appliance)

On the Private Virtual Appliance, users can sign in directly against your directory using the `connection\username` format. Accounts are provisioned just-in-time as Members and de-duplicated by the directory's immutable GUID, so directory renames never fork accounts.

See [LDAP / Active Directory setup](/deployment/appliance/ldap) for the full configuration walkthrough.

***

## External guest verification

External counterparties invited to a secure room authenticate through the guest portal — without ever becoming members of your organization. Depending on what the inviter allows, a guest verifies with:

* **Email one-time password (OTP)** — a code sent to the invited address
* **Google or Microsoft sign-in** — platform OAuth against the invited address
* **Their own organization's IdP** — when the counterparty tenant has SSO configured

The method and resulting identity-assurance level are sealed into the guest's session and visible in the audit trail. See [Secure Rooms](/enclave/rooms) for inviting external parties.

***

## Required roles

| Action                               | Required role |
| ------------------------------------ | ------------- |
| Manage SSO connections               | Owner         |
| Manage LDAP connections (appliance)  | Owner         |
| Invite users / manage local accounts | Owner, Admin  |
| Sign in via any configured method    | Any user      |
