# Okta setup (SAML + SCIM)

Connect your Okta org to LocalCan with a single SAML 2.0 app that handles both sign-in and SCIM provisioning. Takes about 20 minutes, plus DNS propagation.

The Okta app and the LocalCan connection each need values from the other: create the app with placeholders first, register in LocalCan, then paste LocalCan's URLs back into the app.

#### 1. Create the SAML app in Okta

1. In the Okta Admin Console: **Applications → Applications → Create App Integration**.
2. Sign-in method: **SAML 2.0**.
3. App name: `LocalCan`. Check **Do not display application icon to users** (see the tile note below).
4. On the **Configure SAML** step:
   - **Single sign-on URL**: `https://localcan.invalid/placeholder` (replaced in step 3)
   - **Audience URI (SP Entity ID)**: `https://localcan.invalid/placeholder` (replaced in step 3)
   - **Name ID format**: `EmailAddress`
   - **Application username**: `Email` (required: LocalCan identifies users by work email)
   - Leave the rest at defaults.
5. Finish the wizard.
6. On the **Sign On** tab, click **View SAML setup instructions** and copy three values:
   - **Identity Provider Single Sign-On URL**: copy exactly as shown (it contains an `exk…` app key that can't be guessed)
   - **Identity Provider Issuer** (looks like `http://www.okta.com/exk…`)
   - **X.509 Certificate**
7. On the **Assignments** tab, assign the Okta **group** that should have LocalCan access.

> [!NOTE/Okta dashboard tiles]
> SAML app tiles perform IdP-initiated sign-in, which LocalCan rejects by design. For a working tile, create an Okta **Bookmark App** pointing at `https://www.localcan.com/dashboard/login`.

#### 2. Register the connection in LocalCan

1. As the team owner, open your team → **SSO**.
2. The form defaults to SAML 2.0. Paste the three values from Okta:
   - **Sign-on URL**
   - **Issuer / IdP Entity ID**
   - **Signing certificate** (PEM or bare base64 both work; validated at registration, so a paste error fails here rather than at a user's first sign-in)
3. Enter your **email domain(s)**, e.g. `acme.com`. Free email domains are not accepted.
4. Save. LocalCan shows the **Single sign-on URL (ACS)**, the **Audience URI**, and a DNS TXT record.
5. Create the TXT record at your DNS provider, on **every** listed domain, then click **Verify**. The record value is shown once and is valid for 7 days; DNS propagation can take minutes to hours.

#### 3. Finish the handshake in Okta

In the app, go to **General → SAML Settings → Edit** and replace the placeholders:

- **Single sign-on URL** ← LocalCan's **Single sign-on URL (ACS)**
- **Audience URI (SP Entity ID)** ← LocalCan's **Audience URI**

Once your domain is verified, SSO is live: users entering an email on a verified domain are redirected to Okta and back.

#### 4. Enable SCIM (same app)

1. In LocalCan SSO settings, open the **SCIM** panel and click **Generate token**. Copy the **bearer token** (shown once) and the **SCIM base URL**.
2. In Okta: **General → App Settings → Edit**, set Provisioning to `SCIM`, save.
3. On **Provisioning → Integration → Edit**:
   - **SCIM connector base URL**: paste exactly from LocalCan
   - **Unique identifier field for users**: `userName`
   - **Supported provisioning actions**: check **Push New Users** and **Push Profile Updates**
   - **Authentication Mode**: `HTTP Header`; **Authorization**: the bearer token
   - Click **Test Connector Configuration** (must pass), then **Save**.
4. On **Provisioning → To App → Edit**: enable **Create Users**, **Update User Attributes**, and **Deactivate Users**. Leave **Sync Password** off (LocalCan is passwordless).

Done. The group from step 1 now drives both sign-in and provisioning. Okta pushes every current member immediately; each gets a team membership and a license key. See [User lifecycle & seats](/docs/sso/user-lifecycle).

#### Rotating the SCIM token

In LocalCan: SSO settings → SCIM panel → **Rotate token**. The old token stops working immediately. In Okta: update **Provisioning → Integration → Authorization** and re-run **Test Connector Configuration**. The panel shows the token prefix and last-used time, so you can confirm Okta switched.

