Zoho OAuth Token Management for Many Apps
How Zoho access and refresh tokens work, the limits that break multi-app setups and a central token service that avoids them.

Manage every Zoho OAuth token from one place: learn token lifetimes and limits, data centre domains, rotation and a worked token service in Python.
As a Zoho setup grows, so does the number of things that talk to it: a website form handler, an ERP connector, a reporting job, a mobile app, a few scripts someone wrote last year. Each one needs credentials, and each one usually handles them differently. Before long there are refresh tokens in config files, access tokens being generated on every request, and an integration that stops working because another one created too many tokens. Good Zoho OAuth token management fixes this with one clear design: least-privilege clients, a central place that refreshes and caches tokens, secure storage and a plan for rotation and revocation. This guide explains how Zoho's tokens behave, the mistakes we see most, and a worked example of a token service.
How Zoho OAuth tokens work
Zoho CRM uses OAuth 2.0. The OAuth overview and token validity pages describe the details. The essentials:
TokenLifetime and limits (per Zoho's documentation)How to treat itGrant token (authorisation code)One-time use; valid for three minutes by defaultExchange immediately for access and refresh tokensAccess tokenValid for one hour; up to 15 active per refresh token; up to 10 can be generated from a refresh token in 10 minutesCache and reuse until shortly before expiryRefresh tokenDoes not expire until revoked; up to 20 stored per user, with the oldest invalidated when a 21st is createdStore as a secret; never log or share it
Two consequences matter in practice. Generating a new access token for every API call will hit the throttle quickly and cause "Access Denied" errors. And creating refresh tokens repeatedly for the same user can silently invalidate the oldest one, breaking whichever integration was using it.
Data centres and organisations
Zoho runs separate data centres, and tokens must be requested from the accounts server for the user's region, such as accounts.zoho.com, accounts.zoho.eu or accounts.zoho.in. The token response includes an api_domain value that tells you which API domain to call. Zoho's multi-DC documentation explains the setup. Tokens are also specific to an organisation: a refresh token generated for production cannot be used for a sandbox.
Common token management mistakes
- One "admin" refresh token with full scopes shared by every integration
- Refresh tokens stored in source code, spreadsheets or chat messages
- Access tokens generated on every request instead of cached
- Several services refreshing the same token independently and racing each other
- Hard-coded API domains that break for users in another data centre
- No record of which client, user and scopes each integration uses
- Integrations tied to an employee's account, which break when that person leaves
A sound design for multi-app Zoho ecosystems
One client per integration, with minimum scopes
Register a separate client for each integration in the Zoho API console and request only the scopes it needs, for example read-only access to Deals rather than full access to all modules. If one integration is compromised, the damage is contained, and revoking it does not affect the others.
A dedicated integration user
Authorise integrations with a dedicated user whose role and profile limit what it can see and change. Audit logs then show clearly which changes came from integrations.
A central token service
One component, not every script, holds refresh tokens, refreshes access tokens shortly before they expire, caches them and hands them to authorised callers. This respects Zoho's throttles and removes race conditions.
Secure storage
Keep refresh tokens and client secrets in a secrets manager or encrypted store with restricted access and audit logging. The OWASP Secrets Management Cheat Sheet covers good practice.
Connections for Deluge
Inside Zoho, Deluge Connections manage OAuth for you when functions call other Zoho services or external APIs. Use them instead of pasting tokens into scripts.
Worked example: a token service in Python
The illustrative class below caches one access token per integration, refreshes it five minutes before expiry, and uses a lock so concurrent callers never trigger parallel refreshes.
import threading, time, requests
class ZohoTokenService:
def __init__(self, accounts_url, client_id, client_secret, refresh_token):
self.accounts_url = accounts_url # e.g. https://accounts.zoho.in
self.client_id = client_id
self.client_secret = client_secret
self.refresh_token = refresh_token # loaded from a secrets manager
self._token, self._expires_at, self.api_domain = None, 0, None
self._lock = threading.Lock()
def get(self):
with self._lock:
if self._token and time.time() < self._expires_at - 300:
return self._token, self.api_domain
resp = requests.post(f"{self.accounts_url}/oauth/v2/token", data={
"refresh_token": self.refresh_token,
"client_id": self.client_id,
"client_secret": self.client_secret,
"grant_type": "refresh_token",
}, timeout=30)
body = resp.json()
if "access_token" not in body:
raise RuntimeError(f"Token refresh failed: {body.get('error')}")
self._token = body["access_token"]
self._expires_at = time.time() + int(body.get("expires_in", 3600))
self.api_domain = body.get("api_domain", self.api_domain)
return self._token, self.api_domain
Callers use the returned api_domain for API requests and send the token in the Authorization header. If several processes need tokens, run this as a small internal service rather than copying the class into each one. Never log the token values themselves.
Rotation, revocation and offboarding
- Keep an inventory: integration, client ID, authorising user, scopes, where the secret is stored, and the owner
- Rotate client secrets and re-authorise on a schedule, and immediately if a secret may have leaked
- Revoke tokens for integrations that are retired
- Review the inventory when staff leave, especially if any integration was authorised under a personal account
- Alert on repeated authentication failures, which often signal an invalidated token
Choosing the right client type
Zoho offers different client types in its API console. Server-based clients suit web applications where a user authorises access through a browser redirect. Self clients suit back-end scripts and services owned by your own organisation, where you generate the grant token in the console and exchange it once. Choose the type that matches how the integration runs, and record the choice in your inventory so future maintainers know how to re-authorise it.
Monitoring token health
Track token refreshes per integration, refresh failures, and any "Access Denied" or "INVALID_OAUTHTOKEN" errors. A sudden rise usually means a token was revoked, a limit was hit, or a second process is refreshing the same token. Catching it early avoids a quiet backlog of failed syncs. Include these figures on the same dashboard as your other integration health checks.
Testing the design
Test the token service in a sandbox organisation with its own clients and refresh tokens. Simulate expiry by forcing a refresh, run several callers at once to confirm only one refresh happens, and revoke a token to check that alerts fire and the error message is clear. These tests confirm the behaviour you will rely on when something goes wrong in production.
Token handling is one part of a reliable integration; our guide to Zoho CRM API limits covers credits and concurrency. If you are connecting several Zoho and external apps, our guide on when to hire a certified Zoho CRM consultant explains what a multi-app integration project should deliver.
Frequently Asked Questions
How long does a Zoho OAuth access token last?
According to Zoho's documentation, an access token is valid for one hour. Use the refresh token to obtain a new one shortly before it expires.
Do Zoho refresh tokens expire?
Refresh tokens do not expire until they are revoked, but Zoho stores a maximum of 20 per user, and creating more invalidates the oldest.
Why do we get "Access Denied" when refreshing tokens?
Zoho limits how many access tokens can be generated from a refresh token in a 10-minute window. Cache and reuse tokens instead of refreshing on every call.
Should every integration use its own client?
Yes. Separate clients with minimum scopes limit the impact of a compromise and let you revoke one integration without affecting others.
Secure your Zoho integrations with us
We design token management, scopes and secrets handling for multi-app Zoho ecosystems. See our CRM and API integration services, or talk to us about securing your integrations.
About the Author
Manav Sharma is the founder of Insyrge and a CRM solutions architect. He works across Zoho, Salesforce, HubSpot, Odoo and more, designing the CRM setups, integrations and automations that keep sales and operations teams working from the same data.
Need Help Implementing This in Your Business?
Our certified Zoho consultants and automation experts can help you design and deploy custom workflows tailored to your operations.
Book Free Consultation