Skip to main content
Slack plan: Business+ or Enterprise Grid required.
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 [email protected] to learn more.
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 tenant (free tier works)
This guide uses Auth0 as the identity provider. The same pattern applies to other IDPs that support SAML 2.0.

Setting up Slack SSO

In Auth0

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

Open SSO Integrations

In the Auth0 Dashboard, go to Applications > SSO Integrations.
Auth0 Dashboard sidebar showing the SSO Integrations option under Applications
2

Create a new SSO integration

Click Create SSO Integration.
Auth0 Single Sign On Integrations page with the Create SSO Integration button
3

Select Slack Single Sign On

Search for Slack and select Slack Single Sign On.
Auth0 New Single Sign On Integration page showing search results for Slack
4

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
Auth0 New Slack Single Sign On SSO Integration form with Name and Team Name fields
After saving, Auth0 generates the SAML endpoint URL, issuer URI, and signing certificate you need for the next section.

In Slack

1

Open Slack SSO Settings

In Slack, go to Settings & administration > Workspace settings > Authentication > SSO Settings (or your Org-level SSO page on Enterprise Grid).
2

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 fieldAuth0 value
SSO NameA label for the sign-in button, e.g. Auth0
SAML 2.0 Endpoint URLThe Auth0 SAML endpoint, e.g. https://your-tenant.us.auth0.com/samlp/...
Identity Provider Issuer URLThe Auth0 issuer URN, e.g. urn:dev-xxxxx.us.auth0.com
Service Provider Issuer URLhttps://slack.com (default)
Public (X.509) CertificateCopy the full certificate from Auth0
Slack Configure SSO dialog showing SAML fields filled with Auth0 values
3

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)
Slack SSO signing options showing Sign the Assertion checked under SAML Response Signing
4

Test the configuration

Click Test Configuration to verify the connection.
Slack Configure SSO dialog with the Test Configuration button highlighted
5

Apply the configuration

If the test passes, review the configuration and click Apply.
Slack Review SSO configuration showing Everything looks good with Apply button

Signing the SAML response (optional)

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.
To sign the full SAML response:
1

Create a custom SAML application

In Auth0, go to Applications > Applications and create a Regular Web Application.
2

Enable the SAML2 Web App addon

Open the application, go to the Addons tab, and enable the SAML2 Web App addon.
Auth0 Application Addons tab showing the SAML2 Web App addon toggle
3

Set signResponse to true

In the addon settings, find the signResponse property and set it to true.
Auth0 SAML2 Web App addon settings with signResponse highlighted and annotation to switch to true
4

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 section above.
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.

Additional prerequisites

  • A Google (or other) social connection enabled in Auth0
  • A Tightknit API key for your community

In Tightknit Studio

1

Get your Tightknit API key

Open Tightknit Studio, go to Settings > API Keys, and create or copy an existing key.
Tightknit Studio API Keys page showing where to create and copy API keys
This key authenticates requests to the Tightknit membership check endpoint. Customer API keys are scoped to your community, so no additional headers are needed.

In Auth0

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.
1

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.
Auth0 Action editor showing the Tightknit Membership Check code and secrets configuration
Auth0 Action
// 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.
  // ---------------------------------------------------------------
};
2

Add secrets to the action

In the action editor, click the lock icon (Secrets) and add:
SecretValue
TIGHTKNIT_API_KEYYour Tightknit API key from the previous section
domainYour Auth0 tenant domain, e.g. your-tenant.us.auth0.com
clientIdClient ID of an Auth0 M2M app authorized for the Management API
clientSecretClient secret of that M2M app
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.
3

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
Auth0 Triggers page showing the post-login trigger highlighted under Sign Up and Login
Auth0 Post Login flow showing the membership check action between Start and Complete

Force account selection (optional)

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.
1

Disable Auth0 session reuse

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}'
2

Force the Google account picker

# 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"}}}}'
Google Choose an account screen showing the account picker forced by the select_account prompt parameter

Test

1

Sign in as a member

Use Slack SSO with an email that belongs to an active community member. You should be logged into Slack.
Slack single sign-on page with SSO provider button
Auth0 welcome screen showing Continue with Google button
2

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.”
3

Check logs

In Auth0, go to Monitoring > Logs to verify the action ran. Look for console.log output in the event details.

Error codes

When the action redirects to your login page, the error query parameter tells the page which message to display.
CodeMessage
member_not_foundAn account with this email address does not exist.
account_deactivatedYour account has been deactivated. Please contact your administrator.
account_forgottenYour account is no longer available. Please contact your administrator.
service_unavailableUnable to verify your account at this time. Please try again later.
See 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.

Member check returns 401 or 403

Verify the TIGHTKNIT_API_KEY secret is correct. Generate a new key from Studio > Settings > 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.