Zendesk
Zendesk integration¶
Authentication selection¶
Kitsune selects authentication from the configured credentials:
| Configuration | Authentication |
|---|---|
Both ZENDESK_OAUTH_CLIENT_ID and ZENDESK_OAUTH_CLIENT_SECRET are non-empty |
OAuth, even if legacy credentials are also configured |
| Either OAuth value is missing or empty | Legacy email + API token |
The legacy mechanism is HTTP Basic authentication with an email and an API token, not a Zendesk password. Configure it with:
ZENDESK_SUBDOMAIN=your-subdomain
ZENDESK_USER_EMAIL=your-integration-account@example.com
ZENDESK_API_TOKEN=your-api-token
The selected method requires its complete credentials and a subdomain. Missing credentials fail when an API operation is attempted. OAuth authentication errors and timeouts never cause an automatic fallback to legacy credentials.
Run ./manage.py check before deployment. Setting only one OAuth value emits
customercare.W001, warning that legacy authentication will be selected. Set both
values to enable OAuth, or clear both to select legacy authentication explicitly.
OAuth setup¶
When OAuth is selected, Kitsune uses Zendesk's client-credentials flow. It obtains
an access token on the first API operation and caches it until one minute before
its reported expiry. Web and Celery workers reuse tokens through Django's default
cache; configure CACHE_URL to use their shared Redis cache.
In Zendesk Admin Center, under Apps and integrations > APIs > OAuth clients:
- Create a confidential client for this integration and environment.
- Set its allowed scopes to
read users:write tickets:write organizations:write. - Store its Identifier and Secret in the deployment's secret configuration:
ZENDESK_SUBDOMAIN=your-subdomain
ZENDESK_OAUTH_CLIENT_ID=your-client-identifier
ZENDESK_OAUTH_CLIENT_SECRET=your-client-secret
Client-credentials tokens act as the OAuth client's creator. Use the intended integration account, with the permissions required to read tickets, users, and organizations, update users and email identities, and create or update tickets and organizations. No browser callback or refresh token is needed.
Token cache keys include the requested scopes. When deploying expanded scopes, update the OAuth client's allowed scopes first; narrower cached tokens will not be reused.
Rollout and rollback¶
Deploy the code with the existing legacy credentials and both OAuth values empty. To enable OAuth, supply both OAuth values and restart or redeploy both web and Celery workers. Django settings are loaded at process startup; this is not a live switch. Legacy credentials may remain configured during the transition.
Verify ticket creation (authenticated and loginless), replies, synchronization, and user updates in staging. To roll back, clear both OAuth values, ensure the legacy email and API token are still configured and valid, and restart or redeploy both web and Celery workers.
Revoke the old API token once the rollout is complete and no other integration uses it. Legacy authentication is temporary: Zendesk retires API tokens on April 30, 2027.
Webhook authentication and chat-widget signing credentials are separate and do not change.
See Zendesk's OAuth migration guide for the client-credentials flow and token lifecycle.
Using requests to query the API¶
During development being able to query the API manually to fetch details about field IDs, user statuses, and so on is very useful.
Use the authenticated requests.Session from ZendeskClient so manual requests
follow the same authentication selection as the application. For example, in
./manage.py shell_plus:
from django.conf import settings
from kitsune.customercare.zendesk import ZendeskClient
base = f"https://{settings.ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/"
session = ZendeskClient().client.tickets.session
session.get(
base + "ticket_fields.json",
timeout=settings.ZENDESK_SYNC_TIMEOUT,
).json()
# For writes, replace the endpoint and payload with the intended operation.
session.post(
base + "your_endpoint.json",
json={},
timeout=settings.ZENDESK_SYNC_TIMEOUT,
).json()
Create a fresh ZendeskClient and session for a new operation in a long-running
shell session rather than retaining an OAuth-authenticated session past its token
expiry. Do not print or log tokens or client secrets.