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

# Per-Member Authentication

> Configure individual warehouse authentication for team members

## Overview

This guide walks you through configuring per-member authentication for your Snowflake or Databricks connectors. By default, connectors use a single shared credential (service account, key pair, or shared OAuth token) that all team members share. Per-member authentication changes this so that each member queries the warehouse using their own identity, enabling per-user audit trails and row-level security.

When you select **Per-Member OAuth** as the authentication type, members can authenticate in one of two ways:

| Method    | How it works                                                                                | Setup required                                       |
| --------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| **Popup** | Each member completes a one-time browser popup to authenticate directly with the warehouse  | OAuth client credentials on the connector            |
| **SSO**   | Members authenticate automatically using their existing SSO session, with no popup required | OAuth client credentials + SSO token exchange config |

SSO token exchange is an optional enhancement. If configured but the exchange fails for any member, the popup flow remains as a fallback.

## Prerequisites

Per-member OAuth requires an OAuth application registered with your warehouse. This gives TextQL the client credentials needed to initiate the OAuth flow on behalf of each member.

<Note>
  The redirect URIs below use `https://app.textql.com`. If you are running a VPC or custom deployment, replace this with your actual TextQL host (e.g., `https://textql.yourcompany.com`).
</Note>

### Snowflake

Create a Snowflake OAuth Security Integration:

```sql theme={null}
CREATE SECURITY INTEGRATION textql_oauth
  TYPE = OAUTH
  OAUTH_CLIENT = CUSTOM
  OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
  OAUTH_REDIRECT_URI = 'https://app.textql.com/auth/snowflake/callback'
  OAUTH_ISSUE_REFRESH_TOKENS = TRUE
  OAUTH_REFRESH_TOKEN_VALIDITY = 7776000
  ENABLED = TRUE;
```

Retrieve the client credentials:

```sql theme={null}
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('TEXTQL_OAUTH');
```

### Databricks

Create an OAuth application in your Databricks workspace:

1. Go to **Settings > App connections**
2. Click **Add connection**
3. Set the redirect URL to `https://app.textql.com/auth/databricks/callback`
4. Note the **Client ID** and **Client Secret**

## Configuring the Connector

### Step 1: Create or Edit the Connector

Go to **Connectors** in TextQL and create a new Snowflake or Databricks connector, or edit an existing one.

### Step 2: Select Per-Member OAuth

Under **Authentication Type**, select **Per-Member OAuth**. Enter the **OAuth Client ID** and **OAuth Client Secret** from the prerequisite step.

### Step 3: Members Authenticate

Each member visits the Connectors page and clicks **Connect** next to the connector. A browser popup will redirect them to the warehouse to authorize access. After approving, they are connected and subsequent queries work automatically.

TextQL handles token refresh in the background. If a refresh fails, the member will be prompted to reconnect.

## Enabling SSO Token Exchange (Optional)

If your organization uses [SSO (OIDC)](/core/admin/sso) to log in to TextQL, you can configure per-member connectors to use the member's existing SSO session instead of requiring a popup. Members don't need to take any additional action.

### Snowflake

TextQL supports two SSO modes for Snowflake:

#### Direct SSO

The simpler option. TextQL passes the member's identity provider token directly to Snowflake via External OAuth.

**Step 1:** Create a Snowflake External OAuth Security Integration that trusts your identity provider:

```sql theme={null}
CREATE SECURITY INTEGRATION textql_external_oauth
  TYPE = EXTERNAL_OAUTH
  ENABLED = TRUE
  EXTERNAL_OAUTH_TYPE = CUSTOM
  EXTERNAL_OAUTH_ISSUER = '<your-idp-issuer-url>'
  EXTERNAL_OAUTH_JWS_KEYS_URL = '<your-idp-jwks-url>'
  EXTERNAL_OAUTH_TOKEN_USER_MAPPING_CLAIM = 'sub'
  EXTERNAL_OAUTH_SNOWFLAKE_USER_MAPPING_ATTRIBUTE = 'LOGIN_NAME';
```

Ensure each member's identity provider `sub` claim matches their Snowflake user's `LOGIN_NAME`.

**Step 2:** In the connector form, set **SSO Mode** to **Direct SSO**.

<Warning>
  Direct SSO requires your identity provider to issue JWT access tokens (not opaque tokens). Most enterprise IdPs with custom authorization servers support this. Verify with your IdP administrator if unsure.
</Warning>

#### Token Exchange

For more control, TextQL can exchange the SSO token for a Snowflake-scoped token at your identity provider's token endpoint. This is useful when your IdP requires additional scoping or audience restrictions.

**Step 1:** Create a Snowflake External OAuth Security Integration (same as Direct SSO above). Your IdP must also support token exchange. Okta, Entra, Ping, and most enterprise IdPs do.

**Step 2:** In the connector form, set **SSO Mode** to **Token Exchange** and fill in the additional fields:

| Field                       | Description                         | Example                                                |
| --------------------------- | ----------------------------------- | ------------------------------------------------------ |
| **Token Exchange Endpoint** | Your IdP's token endpoint           | `https://yourcompany.okta.com/oauth2/default/v1/token` |
| **Audience**                | Your Snowflake account URL          | `https://xy12345.snowflakecomputing.com`               |
| **Scope**                   | The Snowflake role scope to request | `session:role:ANALYST`                                 |

### Databricks

TextQL can exchange the member's SSO token at the Databricks workspace's OIDC endpoint using identity federation.

**Step 1:** Create an identity federation policy in Databricks that trusts your identity provider's issuer. See the [Databricks documentation on identity federation](https://docs.databricks.com/en/security/auth/identity-federation.html) for details.

**Step 2:** In the connector form, check **Enable SSO Token Exchange**.

The exchange endpoint is derived automatically from your workspace host, so no additional fields are needed.

<Note>
  Databricks token exchange requires your identity provider to issue JWT access tokens. The token's issuer must match the federation policy configured in Databricks.
</Note>

## Testing

After configuring per-member authentication:

1. Open a new incognito/private browser window
2. Log in to TextQL (via SSO if testing token exchange)
3. Navigate to the **Connectors** page
4. **Popup flow:** click **Connect** next to the connector and complete the popup
5. **SSO flow:** verify the connector shows **Via SSO** or **Connected** without a popup
6. Run a query against the connector to confirm it works

## Troubleshooting

### Member sees "Connect" button instead of automatic SSO

* Verify SSO token exchange is configured on the connector (Direct SSO or Token Exchange mode)
* Check that the member logged in via SSO (not via email magic link or Google)
* If using Token Exchange mode, verify the token exchange endpoint is correct

### Token exchange fails and member gets the popup fallback

**Direct SSO:** Verify your IdP issues JWT access tokens, not opaque tokens. Check that each member's IdP identity maps to a valid Snowflake user.

**Token Exchange (Snowflake):** Verify the endpoint, audience, and scope are correct. Check your IdP's logs for errors.

**Databricks:** Verify the identity federation policy exists and trusts your IdP's issuer.

### "Authentication required" after logging in

* The member's SSO session may have expired. Have them log out and back in
* Check that your OIDC configuration in TextQL includes the `offline_access` scope

### Snowflake returns "JWT token is invalid"

* Verify the External OAuth Security Integration is configured with the correct issuer URL and JWKS URL
* Ensure each member has a Snowflake user whose `LOGIN_NAME` matches their IdP identity

### Databricks returns 401 during token exchange

* Verify the identity federation policy is active in Databricks
* Check that your IdP's issuer matches the federation policy's trusted issuer
* Ensure each member has a corresponding Databricks account

## Next Steps

Once per-member authentication is configured, your team members can start querying the warehouse with their own credentials. TextQL automatically handles token caching and refresh, so members only need to authenticate once.

For optimal security:

* Regularly review which members have active tokens on the Connectors page
* Configure appropriate warehouse roles and permissions for each user
* If using SSO token exchange, ensure your OIDC configuration includes the `offline_access` scope for uninterrupted sessions
