# Self-Hosted Setup

End-to-end walkthrough for wiring SAML SSO into a self-hosted sfp deployment (one you run yourself with `sfp server init`).

> SAML is enabled by default on every self-hosted deployment. Signing material is generated during `sfp server init`, the IdP is registered through an HTTP API, and the resulting provider ID and SSO domain are auto-published to every client. There's no config-file editing required.

***

## Prerequisites

* A running self-hosted deployment created with `sfp server init` and brought up with `sfp server start` (V3 or later).
* Admin access to your SAML identity provider.
* An owner-level JWT for the sfp API. The admin user created by `sfp server init` has the `owner` role, which is what `/sfp/api/sso/providers` requires. Application tokens (UUID-format, created via `sfp server application-token create`) are explicitly rejected on this endpoint — only the user JWT works.

  ```bash
  # Sign in once; the token is stored in your OS keyring under service
  # `sfp-pro`, account `supabase-token-<your-email>`.
  sfp server auth login --admin \
    --email admin@<tenant>.local \
    --sfp-server-url https://<your-domain>

  # Extract it into a shell variable for the curl calls below.
  export SFP_JWT=$(sfp server auth display --email admin@<tenant>.local --jwt)
  ```

  > **Headless / WSL / SSH session?** The keyring backend needs an active D-Bus session and a running `gnome-keyring-daemon` (or equivalent). If `sfp server auth display --jwt` errors with `no secret service provider or dbus session found`, prefix with `dbus-launch` or run from a graphical session.

***

## Step 1 — Configure your IdP

Create the SAML application in your identity provider and copy out the **federation metadata URL**.

Pick the matching guide:

* [Microsoft Entra ID](/flxbl/sfp-server/setting-up/saml-authentication/identity-providers/entra-id.md)
* [Okta](/flxbl/sfp-server/setting-up/saml-authentication/identity-providers/okta.md)

Other SAML 2.0 providers follow the same shape — see [Identity Providers](/flxbl/sfp-server/setting-up/saml-authentication/identity-providers.md) for the URL convention and attribute mapping.

When you finish, you should have a metadata URL that looks something like:

```
https://login.microsoftonline.com/<tenant>/federationmetadata/2007-06/federationmetadata.xml?appid=<app>
```

***

## Step 2 — Register the IdP with sfp

One API call hands the metadata URL to sfp:

```bash
curl -X POST "https://<your-domain>/sfp/api/sso/providers" \
  -H "Authorization: Bearer $SFP_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "metadataUrl": "<idp-metadata-url>",
    "domains": ["company.com"]
  }'
```

Auto-detect kicks in immediately — no restart needed. The response contains the provider `id` and the SAML `entityId`.

### Verify

```bash
# List registered providers
curl "https://<your-domain>/sfp/api/sso/providers" \
  -H "Authorization: Bearer $SFP_JWT"

# Confirm /sfp/api/config publishes the SSO settings
curl "https://<your-domain>/sfp/api/config"
# -> sso.providerId and sso.domain are populated
```

### Remove a provider

```bash
curl -X DELETE "https://<your-domain>/sfp/api/sso/providers/<id>" \
  -H "Authorization: Bearer $SFP_JWT"
```

***

## Step 3 — Provision users

Self-registration is disabled by default, so users must be created before they can sign in. `POST /sfp/api/users` is the single entry point — it auto-detects the registered SSO provider and links the user to it:

| User state on call           | What happens                                  |
| ---------------------------- | --------------------------------------------- |
| New user                     | Created with SSO identity.                    |
| Existing email/password user | Converted to SSO; identity linked to the IdP. |
| Existing SSO user            | Idempotent; team membership added if missing. |

Via the API:

```bash
curl -X POST "https://<your-domain>/sfp/api/users" \
  -H "Authorization: Bearer $SFP_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@company.com",
    "firstName": "John",
    "lastName": "Doe",
    "team": "<team-slug>",
    "role": "member"
  }'
```

Or via the CLI:

```bash
sfp server user add \
  --firstname John \
  --lastname Doe \
  --target-email john.doe@company.com \
  --team <team-slug> \
  --role member \
  --email admin@<tenant>.local \
  --sfp-server-url https://<your-domain>
```

***

## Step 4 — Sign in

### CLI

```bash
# One-time configuration
sfp set server-url https://sfp.company.com --global
sfp set server-email user@company.com --global

# Authenticate
sfp auth login --provider saml
```

You don't need to pass `--sso-domain` or `--sso-provider-id` if a provider is registered — the CLI fetches them from `/sfp/api/config`. Override only when needed:

```bash
sfp auth login \
  --email user@company.com \
  --provider saml \
  --sso-domain company.com \
  --sfp-server-url https://sfp.company.com
```

The CLI opens your browser, completes the SAML round-trip, and stores the session in your OS keychain. SAML access tokens expire after about an hour; the CLI refreshes them automatically before expiry and on `401` responses. For long-running CI jobs, you can also force a refresh:

```bash
sfp auth refresh --email user@company.com
sfp auth refresh --all
```

### Web UI

Open `https://<your-domain>` in a browser. The login screen pre-fills the SSO domain from the server config. Click **Continue** to redirect to your IdP.

### Desktop app

Open the desktop app and sign in with SAML — the IdP redirect is captured through the app's custom protocol handler. No extra configuration needed beyond having the provider registered on the server.

***

## API reference

All endpoints below are owner-only unless noted.

### `POST /sfp/api/sso/providers`

Register a SAML IdP. Body:

```json
{
  "metadataUrl": "https://...federationmetadata.xml",
  "domains": ["company.com"]
}
```

Returns `{ id, domains, entityId }`.

### `GET /sfp/api/sso/providers`

List registered providers.

### `DELETE /sfp/api/sso/providers/:id`

Remove a provider.

### `GET /sfp/api/config` *(public)*

Returns the public web-app configuration, including `sso: { domain, providerId }`.

### `POST /sfp/api/users`

Create or link a user. Auto-detects the SSO provider; idempotent on re-runs.

***

## Something not working?

See [Troubleshooting](/flxbl/sfp-server/setting-up/saml-authentication/troubleshooting.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.flxbl.io/flxbl/sfp-server/setting-up/saml-authentication/self-hosted-setup.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
