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

# SAML SSO with Auth0

> Connect Auth0 to KnoxCall over SAML 2.0 — the SAML2 Web App addon, the settings JSON, the NameID Auth0 already gets right, group claims you have to build, assertion encryption, Single Logout and signing-key rotation, with the exact values to paste.

# SAML SSO with Auth0

Auth0 federates as an **Application** with the **SAML2 Web App** addon switched on. Everything KnoxCall needs is three values and a certificate, and all three are published on the addon's **Usage** tab.

**Before you start**

* KnoxCall: an **Enterprise** plan, the **owner or admin** role, and at least one [domain verified for single sign-on](/sso/domains) — a domain you verified for *sending mail* is a different proof and does not admit a login.
* Auth0: a tenant administrator who can create applications and edit addons.

<Note>
  **Auth0 is most often wired over OIDC, and this page is the SAML path.** That is deliberate, not an oversight: the SSO configuration surface in KnoxCall builds **SAML** connections, and a SAML connection is what these steps produce. `tenant_sso_connections` does carry `oidc_issuer`, `oidc_client_id` and `oidc_client_secret_id`, and its `protocol` column accepts `oidc` as well as `saml` — so the data model has room for an OIDC connection — but **no screen and no API on this surface creates one today**, and nothing authenticates one. Do not plan around it. If OIDC is what you need from Auth0, say so on your support thread rather than filling these fields in and expecting a different protocol to come out.
</Note>

<Warning>
  **Configured KnoxCall before 8 September 2026?** Re-enter the values below, or re-import our SP metadata. KnoxCall now **signs AuthnRequests** (RSA-SHA256), publishes an **encryption** key, and publishes a **Single Logout** endpoint. An Auth0 addon configured from the older document has no signature certificate of ours on file, has no encryption key to encrypt to, and has no SLO endpoint of ours to call. None of that is visible from KnoxCall's side. See [the call-out on the overview page](/sso/overview) for the whole story.
</Warning>

## 1. Create the application

**Auth0 Dashboard → Applications → Applications → Create Application.** Choose **Regular Web Application**, name it (for example `KnoxCall`), and create it. You will not use its OIDC credentials — the application object is just the thing the SAML addon hangs off.

Open the new application, go to the **Addons** tab, and switch **SAML2 WEB APP** on. Auth0 opens the addon's configuration.

## 2. Application Callback URL

On the addon's **Settings** tab, the **Application Callback URL** is KnoxCall's assertion consumer service. Replace `acme` with your workspace slug throughout this page.

| Auth0 field                  | Value                                     |
| ---------------------------- | ----------------------------------------- |
| **Application Callback URL** | `https://acme.knoxcall.com/saml/acme/acs` |

The authoritative copy of every KnoxCall value on this page is your own metadata document at `https://acme.knoxcall.com/saml/acme/metadata` — it is public, so fetch it in a browser and read the values off it rather than assembling them by hand.

These are the `default` connection's values — the connection every workspace starts with, and the one the `/saml/<workspace>/…` alias resolves to. If Auth0 is a *second* identity provider for this workspace, it gets its own connection with its own handle, and its values are `/sso/<workspace>/<handle>/{metadata,acs,login,slo}` — for a handle of `auth0`, `https://acme.knoxcall.com/sso/acme/auth0/acs` and its three siblings. Open that connection under **Settings → Single sign-on** and its **Certificates** tab lists all five, each with a copy button. See [more than one identity provider](/sso/overview#more-than-one-identity-provider).

## 3. The settings JSON

Below the callback URL, Auth0 gives you a JSON document rather than a form. Everything else on the IdP side is set here. The keys that matter:

```json theme={"dark"}
{
  "audience": "https://acme.knoxcall.com/saml/acme/metadata",
  "recipient": "https://acme.knoxcall.com/saml/acme/acs",
  "destination": "https://acme.knoxcall.com/saml/acme/acs",
  "nameIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
  "signatureAlgorithm": "rsa-sha256",
  "digestAlgorithm": "sha256",
  "signResponse": false,
  "mappings": {
    "user_id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
    "name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
  }
}
```

**`audience` is KnoxCall's metadata URL, and that is not a typo.** KnoxCall's SP entity ID *is* its metadata URL — that is what the metadata document says. Shorten it to the origin and Auth0's audience will not match the one KnoxCall enforces, and every assertion will be rejected.

**Leave `signResponse` false.** Auth0 signs the assertion either way, which is what KnoxCall requires; signing the response as well is accepted but buys nothing here.

### The NameID: Auth0 already gets this right, and an edit can break it

Auth0's default `mappings` put **`user_id`** on the `…/claims/nameidentifier` claim, and its default `nameIdentifierProbes` reads that claim first. So out of the box the NameID is the Auth0 user id (`auth0|6…`, `google-oauth2|1…`), which is the stable identifier this needs — see [choosing the NameID](/sso/overview#choosing-the-nameid). Of the providers documented here it is the only one whose default is already correct.

Two ways to lose it, both of them edits somebody makes for an unrelated reason:

* **Replacing `mappings` wholesale.** The addon's `mappings` key is a replacement, not a merge. Write a `mappings` object without a `user_id` entry and the nameidentifier claim disappears; `nameIdentifierProbes` falls through to `email`, and from then on the NameID is the address — which changes when a person is renamed, and a NameID that changes gives the renamed person a second KnoxCall account.
* **Setting `nameIdentifierProbes` to `["email"]`,** which some integration guides suggest for providers that require an address. KnoxCall does not.

The Auth0 user id is stable for the life of the identity but it is **not** stable across identities: a person who signs into Auth0 with a username/password identity and later with a Google identity has two user ids, and KnoxCall will see two people. Decide which connection your workforce uses before you roll this out, not after.

**Then check what Auth0 actually sends.** Once step 6 is done, run a sign-in from the connection's **Test** tab in KnoxCall and read the **NameID** in the verdict: a value like `auth0|6…` means you are done; an address means the connection will keep showing its NameID notice, and it will be right to.

### Attribute mappings

KnoxCall reads a plain email and display name and nothing else. Auth0's default mappings already emit both under the standard claim URIs:

| Auth0 profile property | SAML claim KnoxCall reads                                            |
| ---------------------- | -------------------------------------------------------------------- |
| `email`                | `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` |
| `name`                 | `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name`         |

Both claim names are on KnoxCall's default list, so nothing has to be named on the KnoxCall side to read them.

**The email claim is required.** With the NameID set to the Auth0 user id, it is the only place KnoxCall finds the person's address — and admission is decided by that address's domain. An Auth0 user whose profile has no `email` cannot be admitted.

## 4. Group claims: Auth0 sends none until you build one

**An Auth0 SAML assertion carries no group or role claim by default.** Auth0 has no directory groups of its own — roles live in its Authorization Core, and nothing puts them in a SAML assertion unless you say so. Groups are not needed for sign-in; they only decide whether a *new* person lands as **member** or **readonly**, so the simplest correct configuration is to skip them and set a default role on the KnoxCall connection.

If you do want them, add a **Login Action** that writes the names onto the profile, and map that property in the addon:

```js theme={"dark"}
exports.onExecutePostLogin = async (event, api) => {
  const roles = event.authorization?.roles ?? [];
  api.idToken.setCustomClaim('groups', roles);
  api.samlResponse.setAttribute('http://schemas.xmlsoap.org/claims/Group', roles);
};
```

`http://schemas.xmlsoap.org/claims/Group` is one of the claim names KnoxCall checks without being told to. Whatever Auth0 emits for each role — role **names**, above — is what you type as the keys of the group map on the KnoxCall connection.

The map's values are bounded: a group mapped to anything but `member` or `readonly` is refused at save time, because *"…an IdP group may only map to `member or readonly`…"* — those two and no others. Owner and admin are granted by a human on the team page and by nothing else.

## 5. Encrypted assertions (optional)

Auth0's SAML2 addon will encrypt the assertion to KnoxCall's public key. KnoxCall accepts encrypted and plain assertions alike and both take exactly the same path, so this is your call, not ours.

Take the certificate from the `use="encryption"` KeyDescriptor in KnoxCall's metadata document — it is the same certificate as the signing one, published twice on purpose, because an IdP reads one descriptor for each job. Then add its PEM and the public key it carries to the addon's settings JSON, under `encryptionCert` and `encryptionPublicKey`, with `encryptionMethod` left at its default.

An addon configured before 8 September 2026 has no encryption key of ours at all, because our metadata did not publish one — re-read the document before you try.

## 6. Take the Auth0 values back to KnoxCall

Two routes: import Auth0's federation metadata, or type the values by hand. The import is the one that cannot be mis-transcribed.

### Import the federation metadata

The addon's **Usage** tab publishes **Identity Provider Metadata** — one document carrying the issuer, the sign-on endpoint and the signing certificate, at `https://<your-tenant>.<region>.auth0.com/samlp/metadata/<client-id>`. Hand KnoxCall that link, or the document itself:

```http theme={"dark"}
POST /admin/saml/connections/<id>/metadata
{ "url": "https://<your-tenant>.<region>.auth0.com/samlp/metadata/<client-id>" }
```

```http theme={"dark"}
POST /admin/saml/connections/<id>/metadata
{ "xml": "<EntityDescriptor …>" }
```

The call **previews by default** and writes nothing until you send it again with `"apply": true`. What the preview reports, what an import never touches, and every refusal it can answer with are on the [overview](/sso/overview#importing-your-idps-metadata). It is a **snapshot**: nothing re-reads that URL on a schedule, so run the import again when you rotate the tenant signing key.

### Or type the values

The addon's **Usage** tab carries all three. In KnoxCall, **Settings → Single sign-on** → your connection:

| KnoxCall field                                     | Where it is                            | Auth0 value                                                                                           |
| -------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| **IdP sign-in URL**                                | Connection tab                         | **Identity Provider Login URL** (`https://<your-tenant>.<region>.auth0.com/samlp/<client-id>`)        |
| **IdP entity ID (optional)**                       | Connection tab                         | **Issuer** (`urn:<your-tenant>.<region>.auth0.com`)                                                   |
| **Single Logout URL (optional)**                   | Connection tab                         | Auth0's SAML logout endpoint (`https://<your-tenant>.<region>.auth0.com/samlp/<client-id>/logout`)    |
| **Only admit specific domains**                    | Connection tab                         | leave it off to admit every domain you have proven for single sign-on; tick it to narrow to a list    |
| **Create accounts automatically on first sign-in** | Connection tab                         | on, unless you invite everyone by hand                                                                |
| **Default role**                                   | Attributes & groups tab                | `member` or `readonly`                                                                                |
| **IdP signing certificate**                        | Certificates tab → *Add a certificate* | **Identity Provider Certificate**, downloaded from the Usage tab, with or without the BEGIN/END lines |

<Note>
  Auth0's issuer really is a `urn:`, not an address. That is a SAML **entity ID** — a name, not a location; nothing dereferences it, and KnoxCall stores it as given. The two fields that *are* dereferenced, the sign-in URL and the single-logout URL, must both be https and are refused otherwise.
</Note>

Saving needs a re-authentication in the last five minutes; that is expected, and it is the same bar as changing a password.

## 7. Single Logout (optional)

Two directions, configured separately.

* **Auth0 → KnoxCall.** In the addon settings JSON, set `logout` to `{ "callback": "https://acme.knoxcall.com/saml/acme/slo", "slo_enabled": true }`. Auth0 then sends a signed `LogoutRequest` to that endpoint.
* **KnoxCall → Auth0.** Put Auth0's own SLO endpoint into the connection's **Single Logout URL**, as in the table above. It must be https; KnoxCall refuses anything else at save time, because a `LogoutRequest` carries the person's email address as its NameID and the browser is redirected to that URL.

Leave the KnoxCall field empty if you do not want the second direction. Empty means "this connection does not do SP-initiated Single Logout" and it never falls back to the sign-in URL. Either way, signing out of KnoxCall always ends the KnoxCall session — never conditionally on the IdP leg. The full behaviour is in [Single Logout](/sso/overview#single-logout).

## 8. Assign people, then test

Auth0 does not gate a SAML application by assignment the way Entra and Okta do: **anyone who can authenticate to the connections enabled on this application can obtain an assertion.** Two consequences worth acting on before you go live:

* Disable every connection on the application except the one your workforce uses — in particular any database connection with open signup, and any social connection.
* Narrow the KnoxCall side too. Tick **Only admit specific domains** on the connection and list the domains that should be admitted; a person who signs up with an address outside them is refused with *"This email domain is not permitted for SAML sign-in to this tenant."*

Test with one account: open `https://acme.knoxcall.com/saml/acme/login`, sign in, and check the person lands in the workspace with the role you expected. If it fails, the login page names the cause — every message and code is in [troubleshooting](/sso/troubleshooting).

## The Auth0 dashboard tile

Auth0's **Identity Provider Login URL** will accept a sign-in that nobody asked for, which reaches KnoxCall as an **IdP-initiated** sign-in — and that is off unless you turn it on. With it off the person is bounced back to the login page with `saml_idp_initiated_disabled`. Sending people to `https://acme.knoxcall.com/saml/acme/login` instead makes it an ordinary SP-initiated sign-in, which works either way. See [IdP-initiated sign-in](/sso/overview#idp-initiated-sign-in).

## Rotating the Auth0 signing certificate

**Auth0's signing key is the tenant's, not the application's.** Rotating it re-signs every SAML application in that Auth0 tenant at the same instant, so schedule it with the other SAML integrations you own, not against this one alone.

Rotate **add-first**:

1. In Auth0, **Settings → Signing Keys → Rotate signing key**. Auth0 keeps the previous certificate available on the Usage tab while you finish.
2. Copy the new certificate into the KnoxCall connection. Pasting a certificate **adds** it — a connection can hold several active certificates and an assertion signed by any of them verifies.
3. Confirm a sign-in works from the connection's **Test** tab.
4. Retire the old certificate in KnoxCall.

Doing it in that order means there is no instant at which the certificate Auth0 is signing with is not one KnoxCall trusts. Retiring the only active certificate is refused outright: *"This is the connection's only active IdP certificate. Add the new certificate first, then retire this one."*
