# Any SAML provider (https://docs.fuser.studio/docs/teams/sso/saml)

Fuser accepts any identity provider that speaks **SAML 2.0**. If yours has a dedicated guide — [Entra ID](https://docs.fuser.studio/docs/teams/sso/entra.md), [Google Workspace](https://docs.fuser.studio/docs/teams/sso/google.md), [Okta](https://docs.fuser.studio/docs/teams/sso/okta.md) — start there. Otherwise this page is the full contract.

## What your IdP must send [#what-your-idp-must-send]

### Attributes [#attributes]

Attribute names are matched **exactly, with no namespace**. A provider that sends `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`, `urn:oid:0.9.2342.19200300.100.1.3`, or `mail` is sending something Fuser does not read.

| Fuser uses   | Attribute name | Required |
| ------------ | -------------- | -------- |
| Email        | `email`        | Yes      |
| First name   | `givenName`    | No       |
| Last name    | `surname`      | No       |
| Display name | `displayName`  | No       |

The email address must be inside the domain you verify with Fuser, or its subdomains. Assertions carrying an address outside it are rejected — including for guest or federated accounts whose real address belongs to another company. Those members need an account on your verified domain, or an email invitation to Fuser.

### NameID [#nameid]

The NameID is the identifier Fuser stores for the account, and it is what resolves the member on every sign-in after the first — at that point the asserted address is not re-checked. Sending an `email` attribute does not make the NameID unimportant; it makes the *email* correct while the NameID remains the identity key.

Your IdP must guarantee two properties:

* **Unique per person.** Two members must never present the same NameID. A collision signs the second member in as the first, reaching everywhere that account has access — Fuser accounts are not scoped to a single workspace.
* **Stable for a person.** Prefer a persistent identifier or a directory GUID over an email address or a login name, both of which get reassigned. A changed NameID makes the member look new to your provider; they are re-attached by email address on the next sign-in.

Never use the **transient** format. It issues a new value on every sign-in, which means a new account link on every sign-in, accumulating without bound. Sign-in keeps working, so nothing surfaces the problem.

> [!WARNING] Send `email`, and NameID stops being load-bearing
>
> When no `email` attribute is present, Fuser falls back to the NameID and treats it as the member's email address. Two failure modes follow:
>
> * Switch the NameID format to something that is not an email address — persistent, object ID, or the `transient` format that rotates on every sign-in — and every member of that domain is locked out until an `email` attribute exists.
> * A NameID that is an address in your domain but not the member's real one silently attaches them to the wrong identity.
>
> Sending `email` explicitly removes both. Do it even when your NameID is already an email address.

### Signing and encryption [#signing-and-encryption]

* The response must be **signed** — Fuser accepts a signature on the SAML response or on the assertion, and validates it against the certificate you provide at registration.
* Deprecated signature and digest algorithms are **rejected**. Use SHA-256 or stronger; SHA-1 will not pass.
* Assertions must carry **timestamps** (`NotBefore` / `NotOnOrAfter`) and Fuser enforces them, so keep your IdP's clock in sync.
* Assertion **encryption is not required**, and Fuser does not publish an encryption key. Send the assertion signed and unencrypted.

### Request binding [#request-binding]

Fuser sends its authentication request over **HTTP-Redirect** and expects the response back over **HTTP-POST** at the ACS URL.

Only **SP-initiated** sign-in is supported: Fuser matches every response against the request it issued, so an unsolicited assertion is rejected. Leave any "IdP-initiated" or app-tile launch option disabled, and point members at the Fuser sign-in page.

## Set up [#set-up]

    ### Create the application in your IdP [#create-the-application-in-your-idp]

    Create a SAML 2.0 application. Leave the audience and reply URL fields as placeholders for now — you get the real values in step 3.

    Collect three things from your IdP's metadata:

    * Its **entity ID** — an identifier that usually looks like a URL. Fuser never fetches it, so an `http://` scheme is fine.
    * Its **SingleSignOnService** location for the HTTP-Redirect binding. This must be HTTPS.
    * Its **X.509 signing certificate**, in PEM form.

    ### Register the provider in Fuser [#register-the-provider-in-fuser]

    Open **Settings** → **Workspace** → **Security** → **Single Sign-On**, choose **SAML**, and enter your email domain along with the entity ID as **Issuer**, the sign-on location as **Sign-on URL**, and the certificate as **Signing certificate**. Include the certificate's `BEGIN` and `END` lines.

    Click **Add provider**.

    ### Paste Fuser's endpoints back [#paste-fusers-endpoints-back]

    The provider card lists what your IdP needs:

    | Fuser shows                  | Your IdP calls it                                          |
    | ---------------------------- | ---------------------------------------------------------- |
    | **Entity ID / Audience URI** | Audience URI, SP entity ID, or SP identifier               |
    | **ACS URL**                  | Assertion Consumer Service URL, or reply URL               |
    | **SP metadata**              | An importable metadata URL, if your IdP supports importing |

    If your IdP can import SP metadata, use that instead of typing the first two.

    ### Configure attributes [#configure-attributes]

    Add the attribute statements from [What your IdP must send](#what-your-idp-must-send), and set the NameID to a stable value.

    ### Verify the domain and test [#verify-the-domain-and-test]

    Add the TXT record shown on the provider card, wait for **Verified — SSO active**, and sign in from Fuser with an address on that domain.

    See [Verifying the domain with DNS](https://docs.fuser.studio/docs/teams/sso.md#verifying-the-domain-with-dns) for the details.

## Rotating the signing certificate [#rotating-the-signing-certificate]

Fuser stores the certificate you paste at registration and never re-reads your IdP's metadata. It holds exactly one certificate per provider, so when the certificate rolls you remove the provider and add it again with the new one.

**Expect an interruption.** An IdP that publishes old and new certificates simultaneously does not spare you: Fuser can only trust one of them, and re-registering also changes the endpoint URLs and the DNS record, which your IdP cannot pick up on its own. Plan the swap for a quiet window and re-verify the domain immediately afterwards.

Removing and re-adding mints new endpoint URLs and a new DNS record, so plan on re-pasting them in your IdP and verifying the domain again — see [Provider settings are final](https://docs.fuser.studio/docs/teams/sso.md#provider-settings-are-final).

## Troubleshooting [#troubleshooting]

    The **Issuer** in Fuser must equal your IdP's entity ID byte for byte — scheme, case, and any trailing slash included. Copy it out of the metadata rather than typing it.

    Either the certificate in Fuser is not the one signing the assertion, or your IdP is signing with a deprecated algorithm. Confirm the certificate matches the current signing key and that the algorithm is SHA-256 or stronger.

    Fuser matches every assertion to the request it issued and enforces the assertion's validity window. This appears when a member replays a stale response, when IdP-initiated sign-in is attempted, or when the IdP's clock has drifted. Check the clock first.

    The address in the assertion is not inside the verified domain. Usually the `email` attribute is missing and the NameID is not a usable address.

## What's Next? [#whats-next]

  - [SSO overview](https://docs.fuser.studio/docs/teams/sso.md): Domain verification, enforcement, and what members see.

  - [Any OIDC provider](https://docs.fuser.studio/docs/teams/sso/oidc.md): The OpenID Connect path.