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

# Slack SSO with Auth0

> Connect Slack workspace SSO to Auth0 as your SAML identity provider, with optional Tightknit membership verification.

<Info icon="slack">
  **Slack plan:** Business+ or Enterprise Grid required.
</Info>

<Info>
  **Prefer a managed solution?** Tightknit offers a hosted SSO integration that handles identity provider configuration, membership verification, and error handling out of the box, no Auth0 or third-party IDP required. Contact [support@tightknit.ai](mailto:support@tightknit.ai) to learn more.
</Info>

This guide walks through setting up Slack SAML SSO with an external identity provider like Auth0. If you use a social connection (Google, Microsoft) as your login method, you can optionally add a post-login action to verify Tightknit community membership before granting access.

## Prerequisites

* A Slack workspace on the **Business+** or **Enterprise** plan
* An [Auth0](https://auth0.com) tenant (free tier works)

<Note>
  This guide uses Auth0 as the identity provider. The same pattern applies to other IDPs that support SAML 2.0.
</Note>

## Setting up Slack SSO

### In Auth0

Auth0 provides a pre-built Slack SSO integration that handles the SAML configuration for you.

<Steps>
  <Step title="Open SSO Integrations">
    In the Auth0 Dashboard, go to **Applications > SSO Integrations**.

    <Frame caption="Auth0 sidebar: Applications > SSO Integrations">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-sso-integrations-nav.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=af87edca64b013296c201f306dc51477" alt="Auth0 Dashboard sidebar showing the SSO Integrations option under Applications" width="532" height="526" data-path="assets/guides/slack-sso/auth0-sso-integrations-nav.png" />
    </Frame>
  </Step>

  <Step title="Create a new SSO integration">
    Click **Create SSO Integration**.

    <Frame caption="SSO Integrations page">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-sso-integrations-page.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=bb7432d3324a72d7f88f01802545cdc4" alt="Auth0 Single Sign On Integrations page with the Create SSO Integration button" width="2084" height="232" data-path="assets/guides/slack-sso/auth0-sso-integrations-page.png" />
    </Frame>
  </Step>

  <Step title="Select Slack Single Sign On">
    Search for **Slack** and select **Slack Single Sign On**.

    <Frame caption="Search for the Slack SSO integration">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-sso-search-slack.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=1539f8cf6bcfb564c9c746d1047092e2" alt="Auth0 New Single Sign On Integration page showing search results for Slack" width="1490" height="742" data-path="assets/guides/slack-sso/auth0-sso-search-slack.png" />
    </Frame>
  </Step>

  <Step title="Name it and save">
    Enter a **Name** (e.g. `Slack`) and your **Slack Team Name**, then click **Save**:

    * **Business+**: your workspace URL slug, e.g. `your-workspace` (from `your-workspace.slack.com`)
    * **Enterprise Grid**: your Grid org slug with the `.enterprise` suffix, e.g. `your-workspace.enterprise`

    <Frame caption="Configure the Slack SSO integration">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-sso-slack-config.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=5be2a091f74cbc9ae98bbaefea6bddf7" alt="Auth0 New Slack Single Sign On SSO Integration form with Name and Team Name fields" width="2148" height="1206" data-path="assets/guides/slack-sso/auth0-sso-slack-config.png" />
    </Frame>

    After saving, Auth0 generates the SAML endpoint URL, issuer URI, and signing certificate you need for the next section.
  </Step>
</Steps>

### In Slack

<Steps>
  <Step title="Open Slack SSO Settings">
    In Slack, go to **Settings & administration > Workspace settings > Authentication > SSO Settings** (or your Org-level SSO page on Enterprise Grid).
  </Step>

  <Step title="Fill in the SAML fields">
    Click **Configure**. In the SSO dialog that opens, fill in the SAML fields at the top using values from your Auth0 SSO integration:

    | Slack field                      | Auth0 value                                                                |
    | -------------------------------- | -------------------------------------------------------------------------- |
    | **SSO Name**                     | A label for the sign-in button, e.g. `Auth0`                               |
    | **SAML 2.0 Endpoint URL**        | The Auth0 SAML endpoint, e.g. `https://your-tenant.us.auth0.com/samlp/...` |
    | **Identity Provider Issuer URL** | The Auth0 issuer URN, e.g. `urn:dev-xxxxx.us.auth0.com`                    |
    | **Service Provider Issuer URL**  | `https://slack.com` (default)                                              |
    | **Public (X.509) Certificate**   | Copy the full certificate from Auth0                                       |

    <Frame caption="Slack Configure SSO dialog with Auth0 values filled in">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/slack-configure-sso-filled.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=01c05a55210a98a26268f7a806499a4d" alt="Slack Configure SSO dialog showing SAML fields filled with Auth0 values" width="1400" height="1800" data-path="assets/guides/slack-sso/slack-configure-sso-filled.png" />
    </Frame>
  </Step>

  <Step title="Set signing and authentication context">
    Scroll down in the same dialog and set:

    * **AuthnContextClassRef**: Leave as the default (`urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport`)
    * **SAML Request Signing**: Leave unchecked unless your IDP requires signed requests
    * **SAML Response Signing**: Check **Sign the Assertion** (at least one signing option is required)

    <Frame caption="SAML signing options">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/slack-sso-signing-options.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=8640c5666f8804e7d4eb9463806a251d" alt="Slack SSO signing options showing Sign the Assertion checked under SAML Response Signing" width="1248" height="874" data-path="assets/guides/slack-sso/slack-sso-signing-options.png" />
    </Frame>
  </Step>

  <Step title="Test the configuration">
    Click **Test Configuration** to verify the connection.

    <Frame caption="Test Configuration button">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/slack-sso-test-config-button.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=7dcea1910ad37197c699a78f002184fd" alt="Slack Configure SSO dialog with the Test Configuration button highlighted" width="1364" height="242" data-path="assets/guides/slack-sso/slack-sso-test-config-button.png" />
    </Frame>
  </Step>

  <Step title="Apply the configuration">
    If the test passes, review the configuration and click **Apply**.

    <Frame caption="SSO configuration test passed">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/slack-sso-review-success.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=49b0ed02be4e6a0d7529789fd569b65c" alt="Slack Review SSO configuration showing Everything looks good with Apply button" width="1420" height="378" data-path="assets/guides/slack-sso/slack-sso-review-success.png" />
    </Frame>
  </Step>
</Steps>

<h3 id="sign-saml-response">
  Signing the SAML response (optional)
</h3>

<Note>
  **Signing the assertion alone is secure for most deployments.** The assertion is the part of the SAML payload that carries the user's identity and authentication claims, so signing it protects the data Slack actually trusts. Signing the outer response adds a second signature over envelope metadata (issuer, destination, `InResponseTo`) and is defense-in-depth, not a prerequisite — the default Auth0 Slack SSO integration signs only the assertion for this reason.

  Follow the steps below only if your security team explicitly requires `signResponse` (for example, to satisfy an internal SAML hardening policy or a compliance control). Doing so requires replacing the pre-built SSO integration with a custom SAML application.
</Note>

To sign the full SAML response:

<Steps>
  <Step title="Create a custom SAML application">
    In Auth0, go to **Applications > Applications** and create a **Regular Web Application**.
  </Step>

  <Step title="Enable the SAML2 Web App addon">
    Open the application, go to the **Addons** tab, and enable the **SAML2 Web App** addon.

    <Frame caption="Auth0 Application Addons tab with SAML2 Web App">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-addons-saml2.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=0447a4f05d730d6a76796296fadd61e5" alt="Auth0 Application Addons tab showing the SAML2 Web App addon toggle" width="1502" height="866" data-path="assets/guides/slack-sso/auth0-addons-saml2.png" />
    </Frame>
  </Step>

  <Step title="Set signResponse to true">
    In the addon settings, find the `signResponse` property and set it to `true`.

    <Frame caption="Set signResponse to true in the SAML2 addon settings">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-saml2-sign-response.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=ca1b506042d26c6c99d6802e21785b08" alt="Auth0 SAML2 Web App addon settings with signResponse highlighted and annotation to switch to true" width="1364" height="902" data-path="assets/guides/slack-sso/auth0-saml2-sign-response.png" />
    </Frame>
  </Step>

  <Step title="Use the new endpoint in Slack">
    Use the SAML endpoint URL and certificate from this custom application (instead of the SSO integration) when filling in the Slack SSO dialog in the [In Slack](#in-slack) section above.
  </Step>
</Steps>

At this point, Slack SSO is fully configured. Users can sign in to your Slack workspace through Auth0. The remaining steps are optional and cover adding Tightknit membership verification to the login flow.

## Verifying Tightknit community membership (optional)

If you use a social connection (Google, Microsoft, etc.) as the login method in Auth0, anyone with a valid social account can authenticate, even if they are not a member of your community. The steps below add a post-login check that verifies membership via the Tightknit API before granting access.

The full login flow with the membership check in place:

```mermaid theme={null}
sequenceDiagram
    autonumber
    actor User
    participant Slack
    participant Auth0
    participant TK as Tightknit API

    User->>Slack: Sign in with SSO
    Slack->>Auth0: SAML authentication request
    Auth0->>User: Social login prompt (Google, Microsoft, ...)
    User->>Auth0: Authenticate
    Auth0->>TK: POST /admin/v0/members/check<br/>(post-login action)
    TK-->>Auth0: is_member, is_deactivated, is_forgotten
    alt Active member
        Auth0->>Slack: Signed SAML response
        Slack->>User: Signed in to the workspace
    else Non-member, deactivated, or forgotten
        Auth0->>User: Redirect to your community login page<br/>with an error code
    end
```

### Additional prerequisites

* A Google (or other) social connection enabled in Auth0
* A [Tightknit API key](/integrations/api-keys) for your community

### In Tightknit Studio

<Steps>
  <Step title="Get your Tightknit API key">
    Open [Tightknit Studio](https://studio.tightknit.ai/-/integrations/api-keys), go to **Integrations > API Keys**, and create or copy an existing key.

    <Frame caption="Tightknit Studio API Keys page">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/studio-api-keys.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=1a78ea2c2394341343d84c4f46f3068c" alt="Tightknit Studio API Keys page showing where to create and copy API keys" width="3088" height="1914" data-path="assets/guides/slack-sso/studio-api-keys.png" />
    </Frame>

    This key authenticates requests to the Tightknit membership check endpoint. Customer API keys are scoped to your community, so no additional headers are needed.
  </Step>
</Steps>

### In Auth0

<Note>
  **Why is this needed?** If your Auth0 tenant uses a social connection (Google, Microsoft, etc.) as the login method for your SAML application, anyone with a valid social account can authenticate, even if they are not a member of your community. IDPs cannot reject users before the social login completes, so a post-login check is required to verify membership. Without it, non-members see a broken Slack authentication failure instead of a clear error message.
</Note>

<Steps>
  <Step title="Create the post-login action">
    In the Auth0 Dashboard, go to **Actions > Library > Build Custom**. Name it **Tightknit Membership Check**, select the **Login / Post Login** trigger, and paste the code below.

    <Frame caption="Auth0 Action editor with secrets panel">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-action-editor.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=4b99be84695eae196ee8080595268dc4" alt="Auth0 Action editor showing the Tightknit Membership Check code and secrets configuration" width="3790" height="1730" data-path="assets/guides/slack-sso/auth0-action-editor.png" />
    </Frame>

    ```javascript Auth0 Action theme={null}
    // Replace with your community's login page URL
    const LOGIN_PAGE_URL = "https://your-community.tightknit.ai/login";

    exports.onExecutePostLogin = async (event, api) => {
      // ---------------------------------------------------------------
      // Check membership via the Tightknit API.
      // The endpoint returns is_member, is_deactivated, and is_forgotten
      // for the given email address.
      // ---------------------------------------------------------------
      const response = await fetch("https://api.tightknit.ai/admin/v0/members/check", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          // Customer API key, scoped to your community (no tenant header needed)
          "Authorization": `Bearer ${event.secrets.TIGHTKNIT_API_KEY}`,
        },
        body: JSON.stringify({ email: event.user.email }),
      });

      // ---------------------------------------------------------------
      // Fail closed: if the API is unreachable, block the login.
      // ---------------------------------------------------------------
      if (!response.ok) {
        console.log(`Member check failed with status ${response.status}`);
        api.redirect.sendUserTo(LOGIN_PAGE_URL, {
          query: { error: "service_unavailable" },
        });
        return;
      }

      const result = await response.json();
      const isMember = result.data?.is_member === true;
      const isDeactivated = result.data?.is_deactivated === true;
      const isForgotten = result.data?.is_forgotten === true;

      // ---------------------------------------------------------------
      // Not a member: redirect to error page.
      // We use api.redirect.sendUserTo() instead of api.access.deny()
      // because deny() produces a broken SAML response that Slack
      // can't display cleanly. The redirect gives the user a clear,
      // branded error message on the community login page.
      // ---------------------------------------------------------------
      if (!isMember) {
        api.redirect.sendUserTo(LOGIN_PAGE_URL, {
          query: { error: "member_not_found" },
        });

        // Clean up the Auth0 user if it was just auto-created.
        // logins_count === 0 means this is their first attempt.
        if (event.stats.logins_count === 0) {
          try {
            const ManagementClient = require("auth0").ManagementClient;
            const management = new ManagementClient({
              domain: event.secrets.domain,
              clientId: event.secrets.clientId,
              clientSecret: event.secrets.clientSecret,
            });
            await management.users.delete({ id: event.user.user_id });
          } catch (e) {
            console.log(`Failed to delete non-member user: ${e.message}`);
          }
        }
        return;
      }

      // ---------------------------------------------------------------
      // Member exists but account is deactivated or forgotten (GDPR).
      // ---------------------------------------------------------------
      if (isDeactivated) {
        api.redirect.sendUserTo(LOGIN_PAGE_URL, {
          query: { error: "account_deactivated" },
        });
        return;
      }

      if (isForgotten) {
        api.redirect.sendUserTo(LOGIN_PAGE_URL, {
          query: { error: "account_forgotten" },
        });
        return;
      }

      // ---------------------------------------------------------------
      // Active member: allow the login to complete.
      // Auth0 sends the SAML response to Slack and the user is logged in.
      // ---------------------------------------------------------------
    };
    ```
  </Step>

  <Step title="Add secrets to the action">
    In the action editor, click the **lock icon** (Secrets) and add:

    | Secret              | Value                                                           |
    | ------------------- | --------------------------------------------------------------- |
    | `TIGHTKNIT_API_KEY` | Your Tightknit API key from the previous section                |
    | `domain`            | Your Auth0 tenant domain, e.g. `your-tenant.us.auth0.com`       |
    | `clientId`          | Client ID of an Auth0 M2M app authorized for the Management API |
    | `clientSecret`      | Client secret of that M2M app                                   |

    <Warning>
      The `clientId` and `clientSecret` are for a Machine-to-Machine application authorized to call the Auth0 Management API. These are used to clean up orphaned user records, not for the SAML application.
    </Warning>
  </Step>

  <Step title="Deploy and attach to the Login flow">
    * Click **Deploy** in the action editor
    * Go to **Actions > Flows > Login**
    * Drag **Tightknit Membership Check** into the flow after the default login step
    * Click **Apply**

    <Frame caption="Auth0 Triggers page: select the post-login trigger">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-triggers.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=ce9fb3c15eb848b0966eb52dd306ff0e" alt="Auth0 Triggers page showing the post-login trigger highlighted under Sign Up and Login" width="3384" height="1294" data-path="assets/guides/slack-sso/auth0-triggers.png" />
    </Frame>

    <Frame caption="Auth0 Login Flow with the membership check action attached">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-login-flow.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=f0ead208452b94a0d0c2ea81dbc12bc5" alt="Auth0 Post Login flow showing the membership check action between Start and Complete" width="2598" height="1322" data-path="assets/guides/slack-sso/auth0-login-flow.png" />
    </Frame>
  </Step>
</Steps>

<h3 id="force-account-selection">
  Force account selection (optional)
</h3>

By default, Auth0 may skip the login page using a cached session, and Google may auto-select the last used account. To force users to choose every time, run these one-time Management API calls.

Get a Management API token from **Applications > APIs > Auth0 Management API > API Explorer**.

<Steps>
  <Step title="Disable Auth0 session reuse">
    ```bash theme={null}
    curl -X PATCH \
      https://your-tenant.us.auth0.com/api/v2/clients/YOUR_SAML_APP_CLIENT_ID \
      -H "Authorization: Bearer YOUR_MGMT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"sso_disabled": true}'
    ```
  </Step>

  <Step title="Force the Google account picker">
    ```bash theme={null}
    # Get your Google connection ID
    curl https://your-tenant.us.auth0.com/api/v2/connections?strategy=google-oauth2 \
      -H "Authorization: Bearer YOUR_MGMT_TOKEN"

    # Update the connection
    curl -X PATCH \
      https://your-tenant.us.auth0.com/api/v2/connections/GOOGLE_CONNECTION_ID \
      -H "Authorization: Bearer YOUR_MGMT_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"options": {"upstream_params": {"prompt": {"value": "select_account"}}}}'
    ```

    <Frame caption="Google account picker with select_account prompt">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/google-account-picker.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=3f5b172a4f6db60697440f26df74f205" alt="Google Choose an account screen showing the account picker forced by the select_account prompt parameter" width="2290" height="1028" data-path="assets/guides/slack-sso/google-account-picker.png" />
    </Frame>
  </Step>
</Steps>

### Test

<Steps>
  <Step title="Sign in as a member">
    Use Slack SSO with an email that belongs to an active community member. You should be logged into Slack.

    <Frame caption="Slack SSO sign-in page">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/slack-sso-sign-in.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=89a28392a29ac36f178d17d4373f6f01" alt="Slack single sign-on page with SSO provider button" width="2672" height="890" data-path="assets/guides/slack-sso/slack-sso-sign-in.png" />
    </Frame>

    <Frame caption="Auth0 login screen with Google sign-in">
      <img src="https://mintcdn.com/tightknit/0jrZ-kuYZr-AuNwV/assets/guides/slack-sso/auth0-google-login.png?fit=max&auto=format&n=0jrZ-kuYZr-AuNwV&q=85&s=5de5c41a9628bc0da02c6047413ea3a1" alt="Auth0 welcome screen showing Continue with Google button" width="910" height="1202" data-path="assets/guides/slack-sso/auth0-google-login.png" />
    </Frame>
  </Step>

  <Step title="Sign in as a non-member">
    Use an email that is not in your community. You should be redirected to your login page with the message "An account with this email address does not exist."
  </Step>

  <Step title="Check logs">
    In Auth0, go to **Monitoring > Logs** to verify the action ran. Look for `console.log` output in the event details.
  </Step>
</Steps>

## Error codes

When the action redirects to your login page, the `error` query parameter tells the page which message to display.

| Code                  | Message                                                                 |
| --------------------- | ----------------------------------------------------------------------- |
| `member_not_found`    | An account with this email address does not exist.                      |
| `account_deactivated` | Your account has been deactivated. Please contact your administrator.   |
| `account_forgotten`   | Your account is no longer available. Please contact your administrator. |
| `service_unavailable` | Unable to verify your account at this time. Please try again later.     |

See [login error codes](/community-site/authentication#login-error-codes) for the full list.

## Troubleshooting

### Slack shows a broken error page

Verify the action uses `api.redirect.sendUserTo()` and not `api.access.deny()`. The `deny()` method sends a failed SAML response that Slack cannot display.

### Users are auto-logged in without choosing an account

Run the `sso_disabled` and `upstream_params` commands from [Force account selection](#force-account-selection).

### Member check returns 401 or 403

Verify the `TIGHTKNIT_API_KEY` secret is correct. Generate a new key from [Studio > Integrations > API Keys](/integrations/api-keys) if needed.

### Action does not run

Confirm the action is deployed and attached to the Login flow in **Actions > Flows > Login**.

### SAML response signing fails

If Slack rejects the SAML response, check that the certificate in Slack matches the one from Auth0. If you need a signed response (not just a signed assertion), follow the [custom SAML application steps](#sign-saml-response).


## Related topics

- [Guides](/guides/index.md)
- [Single sign-on (SSO)](/community-site/sso.md)
- [Security at Tightknit](/security/overview.md)
- [Authentication](/community-site/authentication.md)
- [Check membership](/api-reference/members/check-membership.md)
