Skip to main content

OAuth Client Setup

ZenSearch's per-user OAuth flows (Atlassian, GitHub, Microsoft 365, Google Workspace, Zendesk) and the Slack workspace install flow need an OAuth client application registered with the upstream provider. For most providers, the platform admin pastes the resulting Client ID / Client Secret / Redirect URL into Admin → OAuth Clients, and the server hot-reloads them within 30 seconds.

This page documents the upstream-side steps for each provider.

Where to find the exact callback URL to register: open Admin → OAuth Clients, pick the provider, and fill in the Redirect URL field with your SERVER_PUBLIC_URL host. The amber Register this URL in {Provider}'s developer console box on that page derives the exact callback URL (the path differs per provider — e.g. Google Workspace uses /api/v1/integrations/google-workspace/... with a hyphen) and offers a one-click copy. Paste that value verbatim into the upstream console. Most providers validate the callback URL as an exact-match string — a trailing slash or path mismatch breaks the flow.

:::info Platform vs per-user vs per-team "Platform OAuth client" = the upstream app itself (one set of Client ID/Secret per deployment). Each individual user then runs through the OAuth flow in-product to grant ZenSearch access to their account; that per-user grant is stored in user_connector_credentials. Platform admins set up the OAuth client once; end users authorize each time they connect. :::

:::warning Slack is not yet wired through Admin → OAuth Clients Slack appears in the admin UI's provider list, but as of this writing the Slack handler still reads its OAuth client from environment variables (SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_OAUTH_REDIRECT_URL) — saving Slack credentials in Admin → OAuth Clients has no effect on the running flow. The Slack section below is included so the upstream-app registration steps live alongside the others; configure ZenSearch's side via env vars until the handler is migrated (tracked under per-user-OAuth Phase 2/3). :::


Atlassian (Jira / Confluence)

ZenSearch uses Atlassian's OAuth 2.0 (3LO) flow. One OAuth integration covers both Jira and Confluence.

Steps

  1. Open the Atlassian Developer Console and click Create → OAuth 2.0 integration.

  2. Name the app (e.g. ZenSearch) and accept the developer terms.

  3. On the Permissions page, scroll down to the API list and click Add next to each of:

    • Jira API — then click Configure and enable: read:jira-work, write:jira-work, read:jira-user.
    • Confluence API — then click Configure and enable: read:confluence-content.all, write:confluence-content, search:confluence, read:confluence-space.summary.

    Don't use the Add Marketplace or custom app modal at the top of the page — that's for enrolling third-party Marketplace apps and is unrelated to OAuth scopes.

  4. AuthorizationOAuth 2.0 (3LO) → set the Callback URL to the exact value shown in the admin page's amber Register this URL box. Save.

  5. Settings → copy the Client ID and Secret.

  6. Paste both into ZenSearch Admin → OAuth Clients → Atlassian (Jira / Confluence) along with your Redirect URL host. Save.

Required scopes

read:jira-work write:jira-work read:jira-user
read:confluence-content.all write:confluence-content search:confluence read:confluence-space.summary
offline_access

One OAuth grant covers both Jira and Confluence — users connect once and the agent's Jira tools (search, get, create, update, comment, transition issues) and Confluence tools (search pages, get/create/update pages) all use the same access token.

offline_access is appended automatically by ZenSearch's authorize URL builder and must be enabled in the Atlassian app for refresh tokens to work. Without it, users will be re-prompted to log in every hour.

Notes

  • A single OAuth integration can serve any number of Atlassian sites — users pick the site at authorize time. The platform admin does not need a separate client per Atlassian Cloud site.
  • Atlassian validates the callback URL as a full exact-match string (host AND path). Don't add a trailing slash.
  • If you previously connected when only the Jira scopes were requested, you'll need to disconnect (Settings → Integrations → Atlassian → Disconnect) and reconnect once. Atlassian doesn't widen scopes on existing tokens.

GitHub

ZenSearch uses GitHub's OAuth App flow (not the GitHub App flow — they are different products).

Steps

  1. Go to GitHub Developer settings → OAuth Apps (or your organization's Settings → Developer settings → OAuth Apps page if you want it owned by an org) and click New OAuth App.
  2. Fill in:
    • Application name: e.g. ZenSearch
    • Homepage URL: your SERVER_PUBLIC_URL
    • Authorization callback URL: the exact value shown in the admin page's Register this URL box.
  3. Click Register application.
  4. On the next screen, copy the Client ID and click Generate a new client secret, then copy the secret.
  5. Paste both into ZenSearch Admin → OAuth Clients → GitHub along with your Redirect URL host. Save.

Required scopes

repo

repo is the minimum that lets the agent's GitHub tools read repository metadata, code search, and issues across both public and private repos the user has access to. ZenSearch validates that GitHub returned the requested scopes and surfaces an error if the user (or org policy) drops them.

Notes

  • Choose between a personal OAuth App (lives under your GitHub user) or an organization OAuth App (Settings → Developer settings under your org). Org-owned apps are easier to hand off when team membership changes — recommended for production.
  • GitHub allows multiple authorization callback URLs only on GitHub Apps, not OAuth Apps. If you run separate dev/staging/prod ZenSearch deployments, register one OAuth App per deployment.

Slack

ZenSearch uses Slack's bot-token OAuth installation flow (one bot install per workspace).

Steps

  1. Go to Slack API → Your Apps and click Create New App → From scratch.

  2. Name the app (e.g. ZenSearch) and pick the development workspace. (You can later distribute it to other workspaces.)

  3. OAuth & PermissionsRedirect URLs → add the exact value shown in the admin page's Register this URL box. Save URLs.

  4. On the same page, scroll to Scopes → Bot Token Scopes and add each of:

    • app_mentions:read
    • chat:write
    • channels:history
    • groups:history
    • im:history
    • mpim:history
    • users:read
    • users:read.email
  5. Basic Information → copy the Client ID and Client Secret under App Credentials.

  6. Set the following on the core-api service and restart:

    • SLACK_CLIENT_ID — Client ID
    • SLACK_CLIENT_SECRET — Client Secret
    • SLACK_OAUTH_REDIRECT_URL — the callback URL you registered (must match exactly)

    Slack does not yet read from the platform OAuth Clients DB row (see the warning at the top of this page); env vars are the source of truth for now.

Required scopes

app_mentions:read chat:write channels:history groups:history
im:history mpim:history users:read users:read.email

Notes

  • For multi-workspace installs (cloud SaaS pattern), the same OAuth client serves any workspace that runs through the install flow — no need for one client per customer.
  • For single-workspace self-hosting, you can skip distribution and install directly into your one workspace.
  • The callback URL the admin page derives for Slack (/api/v1/integrations/slack/auth/callback) is the correct value to paste into both the Slack app's Redirect URLs list and your SLACK_OAUTH_REDIRECT_URL env var.

Microsoft 365

ZenSearch uses Azure AD (Entra ID) app registration with delegated Microsoft Graph permissions.

Steps

  1. Open the Azure Portal → Azure Active Directory → App registrations and click New registration.

  2. Fill in:

    • Name: e.g. ZenSearch
    • Supported account types: choose Multi-tenant if your users span multiple tenants, or Single-tenant for a locked-down deployment.
    • Redirect URI: select Web and paste the exact value shown in the admin page's Register this URL box.
  3. Click Register. On the resulting Overview page, copy:

    • Application (client) ID → Client ID in ZenSearch
    • Directory (tenant) ID → set M365_OAUTH_TENANT_ID (or common for multi-tenant)
  4. Certificates & secretsNew client secret → copy the Value immediately (it is only shown once).

  5. API permissionsAdd a permissionMicrosoft GraphDelegated permissions, then add the permissions matching the surfaces you want the agent to use (only request what you need):

    SurfaceRequired Graph permissions
    OneDriveFiles.ReadWrite.All
    MailMail.ReadWrite, Mail.Send
    CalendarCalendars.ReadWrite
    TeamsChannelMessage.Send, Channel.ReadBasic.All, Team.ReadBasic.All, Chat.ReadWrite
    MeetingsOnlineMeetings.Read, OnlineMeetingTranscript.Read.All, OnlineMeetingArtifact.Read.All, Chat.Read
    To-DoTasks.ReadWrite
    PeoplePeople.Read
    SharePointSites.ReadWrite.All

    ZenSearch always appends offline_access, openid, and User.Read automatically.

  6. If your tenant requires admin consent for any of the permissions, click Grant admin consent at the top of the API permissions page.

  7. Paste Client ID and Client Secret into ZenSearch Admin → OAuth Clients → Microsoft 365 along with your Redirect URL host. Set M365_OAUTH_TENANT_ID in .env if you need to pin a tenant.

Notes

  • Multi-tenant apps must be verified by Microsoft to appear in third-party tenant consent screens — for internal-only deployments, single-tenant is simpler and avoids verification.
  • The client secret has a max lifetime of 24 months; rotate before expiry.

Google Workspace

ZenSearch uses Google's OAuth 2.0 web application flow with delegated user consent.

Steps

  1. Open the Google Cloud Console → APIs & Services → Credentials for the project you want to own the client (create one if needed).
  2. OAuth consent screen → configure with your app name, support email, and developer contact. Add your domain to Authorized domains.
  3. Add the required Scopes to the consent screen (see table below). Save.
  4. CredentialsCreate credentials → OAuth client IDApplication type: Web application.
  5. Add the exact value shown in the admin page's Register this URL box to Authorized redirect URIs. Click Create.
  6. Copy the Client ID and Client Secret from the popup (the secret is also visible later in the credentials list).
  7. Paste both into ZenSearch Admin → OAuth Clients → Google Workspace along with your Redirect URL host. Save.
  8. On the Google Cloud project, enable each API your scopes need (e.g. Google Drive API, Gmail API, Calendar API, Sheets API, Docs API) under APIs & Services → Library.

Required scopes

SurfaceScope
Sheetshttps://www.googleapis.com/auth/spreadsheets
Docshttps://www.googleapis.com/auth/documents
Gmailhttps://www.googleapis.com/auth/gmail.modify
Calendarhttps://www.googleapis.com/auth/calendar.events
Drive (write to files the user creates)https://www.googleapis.com/auth/drive.file
Drive (read everything the user has)https://www.googleapis.com/auth/drive.readonly

ZenSearch always appends openid, https://www.googleapis.com/auth/userinfo.email, and https://www.googleapis.com/auth/userinfo.profile for identity resolution — these match what shows up on Google's consent screen and in your project's credential settings.

Notes

  • An OAuth consent screen marked External in Testing mode only allows users on your Test Users list — promote to In production to allow general workspace users (Google may require app verification depending on the scope set).
  • For a Workspace-only deployment, set the consent screen to Internal instead of External — no verification required, and only members of your Workspace organization can authorize.

Zendesk

Zendesk OAuth clients are registered per Zendesk account (subdomain), not centrally. If your ZenSearch deployment serves users across multiple Zendesk accounts, register one OAuth client in each — they can share the same Client ID string but the secret will differ per account.

Steps

  1. Sign in to your Zendesk Admin Center: https://{subdomain}.zendesk.com/admin/apps-integrations/apis/zendesk-api.
  2. Open the OAuth Clients tab → Add OAuth client.
  3. Fill in:
    • Client Name: e.g. ZenSearch
    • Description: optional
    • Company: your company name
    • Unique Identifier: a stable string (this becomes part of the Client ID) — pick something like zensearch
    • Redirect URLs: add the exact value shown in the admin page's Register this URL box.
  4. Save. Zendesk shows the Secret once on the next screen — copy it immediately.
  5. The Client ID is the Unique Identifier you chose (sometimes shown as the value of unique_identifier in the resulting client row).
  6. Paste both into ZenSearch Admin → OAuth Clients → Zendesk along with your Redirect URL host. Save.

Required scopes

read write hc:read

read write covers tickets and users; hc:read covers Help Center articles. ZenSearch's authorize URL builder maps the tickets and help_center short names onto these.

Notes

  • The Zendesk subdomain is supplied by the end user when they connect (the connector form prompts for it), so the platform OAuth client doesn't need to be subdomain-aware — but the OAuth client must exist under the same subdomain the user types in.
  • If you operate a single Zendesk account (typical for self-hosted deployments), one OAuth client is all you need.

Troubleshooting

"redirect_uri mismatch" or 400 on callback

The most common cause is the path or trailing-slash mismatch. The Register this URL box on the admin page derives the exact callback URL from the Redirect URL field — copy that value verbatim into the upstream console, including the path. If you change SERVER_PUBLIC_URL, you must update the registration in every provider's console.

Hot reload didn't pick up the new credentials

The server caches resolved OAuth client rows for 30 seconds. Wait that long, or restart the core-api service to force an immediate reload. The admin UI's Source badge flips from Not configured / From env to Configured once the server sees the new row.

"OAuth client not configured" 400 in production

Check the Source badge for the provider on Admin → OAuth Clients. If it says Not configured, the row is missing or failed to decrypt. If it says Resolution error, the saved row exists but couldn't be decrypted with the current CREDENTIAL_ENCRYPTION_KEY — re-saving with the current key clears the error.

Rotating credentials

To rotate a Client Secret: generate a new secret in the upstream console, paste it into the admin form (Client ID stays the same), Save. Existing user-issued tokens remain valid until they expire and refresh — only future authorize flows use the new secret.