Welcome back to another week of Kaizen!!
This week, we are diving into how to implement secure user authentication using
Login with Zoho and integrate it with
Zoho CRM through our
Python SDK.
To ground this in a real-world scenario, we will look at how Zylker Academy, a training institute offering web design and development courses, uses an internal portal that connects directly to Zoho CRM. This setup allows course coordinators to manage student data without maintaining a separate backend database.
Zylker receives frequent student enquiries and uses Zoho CRM to manage all related information. Every course coordinator, academic advisor, and support staff member who needs access to student information is added as a user in Zoho CRM, with access permissions aligned to their role. Instead of using Zoho’s interface directly, Zylker’s team works through a custom internal web portal, tailored to their workflow. This portal connects directly to Zoho CRM, reading from and writing to it, but does not have its own database.
But before this portal can access any CRM data, it must authenticate itself securely. Every time a user opens the portal, they must log in with their Zoho account. Once authenticated, they will be granted access to the CRM modules and records they are authorized to work with. That is where Login with Zoho comes in.
What is "Login with Zoho"?
Login with Zoho is Zoho’s implementation of the OAuth 2.0 Authorization Code flow. It allows applications to authenticate users and access their Zoho CRM data without ever handling their passwords.
Instead of asking users for their Zoho credentials directly, the app redirects them to Zoho’s login screen. Here is how it works:
- The app redirects the user to Zoho’s login page.
- The user logs in and approves the requested permissions (scopes).
- Zoho sends back an authorization code.
- The backend exchanges this code for access and refresh tokens.
- These tokens are used to make authenticated API calls.
This flow ensures that users maintain full control over their data. They can revoke access at any time, and your application never handles or stores passwords.
In Zylker’s case, every time a coordinator opens the portal, they are prompted to log in with their Zoho account. Once authenticated, they can immediately begin working with student records—all backed by Zoho CRM.
Use Case Implementation: Zylker’s Student Management Portal
To demonstrate how this login flow works, we have built a stripped-down version of Zylker's portal:
- A front-end form to enter and view student data
- A backend server that interacts with Zoho CRM via the Zoho CRM Python SDK
The application includes a simple form for capturing student details—name, college, course, email, and phone number. Submitted data is treated as a Lead in Zoho CRM.
The app allows users to:
- Add new leads
- View a list of all registered leads
- Edit an existing lead’s information
- Delete records if necessary
All actions go straight to Zoho CRM using its Python SDK. But before any of this can happen, the user must complete the login flow.
Sample Project Structure
Before going into the implementation details, let us briefly define the components of the project.
Frontend
The frontend is a simple static web interface built with HTML, CSS, and JavaScript. It runs in the browser and handles user interactions and triggers backend API calls. These are the main files:
- index.html : Main UI for login, data entry, and record viewing.
- script.js : Contains the client-side logic to trigger login, submit data, and render records.
- redirect.html : A minimal page used to capture the authorization code returned by Zoho after login.
The frontend is served using any static server (e.g., Live Server in VS Code) and runs on
http://localhost:5501/ in our example.
Download the files from
here.
Configuration Notes:
- In script.js, update the redirect_url value in the login request to match your actual domain or port if you’re not using localhost:5501.
- Ensure the URL in the Zoho API Console matches this redirect URI and port.
Backend
The backend is a Python server that handles all interactions with Zoho CRM via the Python SDK. It includes:
- server.py : A custom HTTP server that:
- Generates the Zoho login URL
- Exchanges the authorization code for tokens
- Initializes the SDK
- Exposes endpoints like /create, /get_records, /update, and /delete
- record.py : Contains functions to create, fetch, update, and delete records in CRM modules like Leads. Each function uses the Zoho Python SDK methods to perform a specific operation.
Download the files from
here.
Configuration Notes:
- In server.py, replace the client_id with your actual client ID from Zoho's API Console.
- In record.py, replace the client_secret with your actual client secret.
- If required, change the front-end server’s host and port in the run() function at the bottom of server.py:
def run(server_class=HTTPServer, handler_class=SDKInitialize, port=xxxx):
Sample project flow
Step 1: Register the application with Zoho API console
To initiate the login process, you need to register your application on the
Zoho API Console. This is a one-time setup that provides your app with a
Client ID and
Client Secret, both of which are required to authenticate users and exchange authorization codes for tokens.
To register your application:
We will be using these values in the backend script (server.py) that handles token exchange.
NOTE: To support users from multiple data centres, make sure to enable multi-DC support for your application. You can do this by going to your app’s settings in the Zoho API Console and turning on the Multi-DC option.Step 2: Implementing the login flow
Here is a walkthrough of the flow implemented in the project:
1. Page loads and triggers login
When a user opens the portal, the frontend automatically initiates the login sequence. It first makes a call to the backend to retrieve the Zoho authorization URL.
In index.html, this triggers getRecords() on page load:
- <body onload="getRecords();">
In script.js, getRecords() calls the login() function:
- async function getRecords() {
- login();
- }
The login() function sends a request to the backend to get the Zoho OAuth authorization URL.
2. Backend builds login URL
The backend responds with an OAuth URL that includes:
- Your client ID
- Scopes like ZohoCRM.modules.ALL
- The redirect URI
In server.py, under do_GET, the /login endpoint generates the OAuth URL:
- if parsed_url.path == '/login':
- redirect_url = query_params.get('redirect_url', [''])[0]
- scope = "ZohoCRM.settings.fields.ALL,ZohoCRM.modules.ALL,ZohoCRM.users.READ,ZohoCRM.org.READ"
- url = "https://accounts.zoho.com/oauth/v2/auth?scope=" + scope + "&client_id=" + self.client_id + \
- "&redirect_uri=" + redirect_url + "&response_type=code&access_type=offline"
- self._set_headers()
- # Send response
- response = {"url": url, "redirect_url": redirect_url}
- self.wfile.write(json.dumps(response).encode('utf-8'))
Once the frontend (script.js) receives the login URL, it opens it in a popup window.
- const response = await fetch('http://127.0.0.1:8085/login?redirect_url=http://127.0.0.1:5501/redirect.html');
- const data = await response.json();
- const popup = openCenteredPopup(data.url, "PopupWindow", 600, 400);
Here's an example of the Zoho OAuth authorization URL format:
scope=ZohoCRM.modules.ALL&
client_id=YOUR_CLIENT_ID&
response_type=code&
access_type=offline&
redirect_uri=YOUR_REDIRECT_URI
3. User logs in on Zoho
The user logs in with their Zoho credentials and is prompted to approve the app's access. Once they approve, Zoho redirects them to the specified redirect URI along with an authorization code and location parameter. The location parameter indicates which data centre the user belongs to.
4. Frontend captures the authorization code
The redirect page, a minimal HTML file (redirect.html), reads the URL parameters and stores them in localStorage, then closes the popup:
- function setAccessToken() {
- var hashProps = getPropertiesFromURL();
- if (hashProps) {
- for (var key in hashProps) {
- if (hashProps.hasOwnProperty(key)) {
- localStorage.setItem(key, hashProps[key]);
- }
- }
- }
- setTimeout(function () { window.close(); }, 0);
- }
5. Token exchange and SDK initialization
Once the popup window is closed, the main window retrieves the authorization code and location and sends them to the backend’s /initialize endpoint.
In script.js:
- var code = localStorage.getItem("code");
- var location = localStorage.getItem("location");
- initialize(code, location, data.redirect_url);
- .
- .
- async function initialize(code, location, redirect_url) {
- const response = await fetch('http://127.0.0.1:8085/initialize?code=' + code + '&location=' + location + '&redirect_url=' + redirect_url);
- }
In server.py, the /initialize endpoint handles SDK initialization:
- elif parsed_url.path == '/initialize':
- code = query_params.get('code', [''])[0]
- location = query_params.get('location', [''])[0]
- redirect_url = query_params.get('redirect_url', [''])[0]
- LeadsRecords().init(self.client_id, code, location, redirect_url)
In record.py, the SDK is initialized and tokens are stored.
- token = OAuthToken(client_id=client_id,
- client_secret=client_secret,
- grant_token=code,
- redirect_url=redirect_url)
- Initializer.initialize(environment=environment,
- token=token,
- logger=logger,
- store=store) # FilePersistence or custom store
This exchanges the authorization code for:
- An access token (valid for one hour)
- A refresh token (used to get new access tokens)
These tokens are saved in a local file (sdk_tokens.json). This is configured using Zoho’s FilePersistence class during SDK initialization
How are tokens linked to users?
The SDK maps each access and refresh token pair to a unique user-organization combination. This means tokens generated for different organizations by the same user are stored separately. Likewise, if a user generates new tokens for the same organization, the SDK updates the existing tokens instead of creating duplicates. This ensures that API calls always use the correct tokens tied to the authenticated user and their organization.
To enable this mapping, the SDK retrieves the user and organization information in the background. This requires the appropriate scopes to be included during authentication, ZohoCRM.users.READ and ZohoCRM.org.READ. Without these scopes, the SDK cannot identify the user-org combination correctly, which can lead to multiple token entries for the same user. That is why, in our sample project, we have included these scopes explicitly in the server.py file during the SDK initialization.
Once the SDK is initialized, the user is logged in, and the app can begin making CRM API calls on their behalf.
Step 3: Accessing Zoho CRM
Once the user is authenticated and the Zoho SDK is initialized on the backend, the frontend can call custom backend endpoints like /create or /get_records. These endpoints use the authenticated SDK instance to make CRM API calls on behalf of the user.
- GET /get_records?module=Leads : View all students
- POST /create?module=Leads : Add new student
- PUT /update?module=Leads&id=... : Edit existing entry
- DELETE /delete?module=Leads&id=... : Remove existing entry
Deploying the sample project
To run this application, you will need two components:
- A frontend server to serve your HTML files (index.html, script.js, redirect.html). This can be done using any static web server (e.g., Live Server in VS Code).
- A Python backend server that handles login, token storage, and CRM API communication. You can run it using:
python server.py
In the given example, both servers communicate over localhost. You should set your redirect URI accordingly when registering your app in the Zoho console.
Conclusion
Login with Zoho is a secure, OAuth-based mechanism that allows users to authorize your application to access their Zoho CRM data. In this example, we built a real-world use case, a student portal for Zylker Academy, that authenticates users and interacts with CRM directly using the Zoho CRM Python SDK.
By walking through the entire flow, you now understand:
- Why OAuth is essential for secure CRM access
- How to register an application in Zoho
- What the login and token exchange flow looks like
- How to implement "Login with Zoho" in your applications
What is next?
In this project, we have used a simple file persistence method to store the token files. But in a real world scenario, this may not always meet your business requirements. In next week's Kaizen, we will implement custom token persistence instead of file persistence in the current project. We will explain how to implement this using SQLite, In-Memory and List DBs. With that, you will be equipped to implement a persistence method that fits your application architecture and deployment environment.
We hope that you found this useful. If you have any queries, let us know the comments below, or send an email to
support@zohocrm.com. As always, we would love to hear from you!!
Stay tuned for next week's Kaizen : Implementing Custom Token Persistence
Download Links:
Further Reading:
Recent Topics
Ticket to article and Ticket to template
Hello! I would like to know if it is possible (and how) to do the following actions: 1. To generate an article from a ticket (reply + original message) 2. Easy convert an answer to an email template
Is there API Doc for Zoho Survey?
Hi everyone, Is there API doc for Zoho Survey? Currently evaluating a solution - use case to automate survey administration especially for internal use. But after a brief search, I couldn't find API doc for this. So I thought I should ask here. Than
WebDAV / FTP / SFTP protocols for syncing
I believe the Zoho for Desktop app is built using a proprietary protocol. For the growing number of people using services such as odrive to sync multiple accounts from various providers (Google, Dropbox, Box, OneDrive, etc.) it would be really helpful
Change the "from" field
Hello, I used some random word to create the account ID to later host the domain based emails. That username shows up in the "from" field on test emails. How do I change that to a custom one, like first name/last name or business name? I tried to create second user and "named" it the way I want and it worked to a degree, although the "from" field shows all lower case letters, while original had some capital letters. So the "all-low-case" is another issue I am having... Thank you
[Free Webinar] Learning Table Series - AI-Enhanced Logistics Management in Zoho Creator
Hello Everyone! We’re excited to invite you to another edition of Learning Table Series, where we showcase how Zoho Creator empowers industries with innovative and automated solutions. About Learning Table Series Learning Table Series is a free, 45-60
How to use Rollup Summary in a Formula Field?
I created a Rollup Summary (Decimal) field in my module, and it shows values correctly. When I try to reference it in a Formula Field (e.g. ${Deals.Partners_Requested} - ${Deals.Partners_Paid}), I get the error that the field can’t be found. Is it possible
Zoho Creator to Zoho CRM Images
Right now, I am trying to setup a Notes form within Zoho Creator. This Notes will note the Note section under Accounts > Selected Account. Right now, I use Zoho Flow to push the notes and it works just fine, with text only. Images do not get sent (there
Error Logs / Failure logs for Client Scripts Functions
Hi Team, While we are implementing client scripts for the automation, it is working fine in few accounts but not working for others. So, it would be great if we can have error Logs for client scripts also just like custom functions. Is there any way that
Zoho Books blocks invoicing without VeriFactu even though it is not mandatory until 2027
I would like to highlight a very serious issue in Zoho Books for Spain. 1. The Spanish government has postponed the mandatory start of VeriFactu to January 1st, 2027. This means that during all of 2026 businesses are NOT required to transmit invoices
Problem : Auto redirect from zoho flow to zoho creator
Hi there, I've been waiting for zoho team to get back on this for last couple of days. Anyone else have the problem to access zoho flow? everytime I click on zoho flow it redirects me to zoho creator. I tried incognito mode but it still direct me to zoho
Why am I seeing deleted records in Zoho Analytics syncing with Zoho CRM?
I have done a data sync between Zoho CRM and Zoho Analytics, and the recycle bin is empty. Why do I see deleted leads/deals/contacts in Zoho Analytics if it doesn't exist in Zoho CRM? How can I solve this problem? Thanks
Zoho Books is now integrated with Zoho Checkout
Hello everyone, We're glad to be announcing that Zoho Books is now integrated with Zoho Checkout. With this integration, you can now handle taxes and accounting on your payment pages with ease. An organization you create in Zoho Checkout can be added to Zoho Books and vice-versa. Some of the key features and benefits you will receive are: Seamless sync of customer and invoice data With the end-to-end integration, the customer and invoice details recorded via the payment pages from Zoho Checkout
Sync Issue
My Current plan only allows me with 10,000 rows and it is getting sync failure how to control it without upgrading my plan
Add Zoho PDF to Zoho One Tool Applications
It should be easy to add from here without the hassle of creating a web tab:
JOB WISE INVOICE PROCESS
I WANT TO ENABLE JOB WISE TRACKING OF ALL SALES AND PURCHASE
PDF Template have QTY as first column
I want to have the QTY of an item on the sales orders and invoices to be the first column, then description, then pricing. Is there a way to change the order? I went to the Items tab in settings but don't see how to change the order of the columns on
RAG (Retrieval Augmented Generation) Type Q+A Environment with Zoho Learn
Hi All, Given the ability of Zoho Learn to function as a knowledge base / document repository type solution and given the rapid advancements that Zoho is making with Zia LLM, agentic capabilities etc. (not to mention the rapid progress in the broader
In App Auto Refresh/Update Features
Hi, I am trying to use Zoho Creator for Restaurant management. While using the android apps, I reliased the apps would not auto refresh if there is new entries i.e new kitchen order ticket (KOT) from other users. The apps does received notification but would not auto refresh, users required to refresh the apps manually in order to see the new KOT in the apps. I am wondering why this features is not implemented? Or is this feature being considered to be implemented in the future? With the
IMAP mail after specify date
Hi My customer's mail server is on premise and mail storage is very huge. So It never finish sync. and finally stop sync. Cloud CRM have a option like zoho mail sync mail after some date.
Claude + MCP Server + Zoho CRM Integration – AI-Powered Sales Automation
Hello Zoho Community 👋 I’m excited to share a recent integration we’ve worked on at OfficehubTech: ✅ Claude + MCP Server + Zoho CRM This integration connects Zoho CRM with Claude AI through our custom MCP Server, enabling intelligent AI-driven responses
Search Bar positioning
Why is the Search bar on the far right when everything is oriented towards the left?
Import Error: Empty values for mandatory fields - Closing Date
Hello, I've tried multiple times to import a CVS Potential list from another Zoho account. But the error message I get is: Empty values for mandatory fields - Closing Date There are valid dates in this field, so I don't understand why this error messages
Feature Requests - Contact Coloured Picklist Visibility & Field Visibility During Ticket Creation
Hi Desk Team, I have 2 feature requests for you. Since Coloured Picklists are now available in Desk, It would be great if the colours were visible on the Related Details (Contact Information) when creating a ticket. In the screenshot below, I have 2 fields
Accounts Receivable Balances Differs in Balance Sheet, Customer Balance Report, AR Ageing Summary, and AR Ageing Details.
Hello Zoho Accounts Receivable Balances Differs in Balance Sheet, Customer Balance Report, AR Ageing Summary, and AR Ageing Details. Please clarify and fix the issues here. Thanks
How to integrate XML with Zoho CRM
Hi, I have an eCom service provider that gives me a dynamic XML that contains order information, clients, shipments... The XML link is the only thing I have. No Oath or key, No API get... I want to integrate it into Zoho CRM. I am not a developer nor
Feature Request - Ability to Customise Contact Info Card on Ticket Details View
Hi Desk Team, I've added a "Contact Priority" and "Account Prioirty" field and it would be very useful to agents if they could see that information in the Contact Info card on the Ticket Details view. It would be great if we could choose some fields to
Zoho Flow integration with Facebook Messenger and Whatsapp
Hi there, any plans of adding integrations with Facebook Messenger and Whatsapp into Zoho Flow? Seems that more and more business are delivering automated updates such as "your order is received", "your order has been shipped" and so on via these two platforms. Not sure if Whatsapp has the API access needed i am pretty sure that Facebook Messenger has... Kind regards Bo Thygesen
Campaigns unsubscribe/manage preferences links
Hi, Where can I edit the unscubscribe and manage preferences link in the footer of the email. I would like it so that when you click 'manage preferences' an form opens up that allows the person to choose what type of emails they do and don't wish to
email address somehow still not verified (?!)
L.S. After creating a new email template in CRM I was about to send a group email to my clients, then Zoho CRM announced that they would change the sender address to some kind of Zoho-e-ddress because my email address "has not been verified". Not only
Marketing Tip #17: Add credibility to your online store with Review Widgets
One of the fastest ways to build trust in an online store is to show real customer feedback right where people are deciding to buy. Third-party widgets let you embed things like Google Reviews, Instagram feeds, or even a WhatsApp chat button. These add
adding several team members to an Opportunity
How can we add several team members to one opportunity for collaboration? I have researched and only found something called Deal Team which I cannot find in my CRM to configure.
Bulk update Profile Permissions
Dears, What should we do if we add new forms or reports and need to update more than 20 permissions? Updating them one by one feels pretty harsh, doesn’t it?
Filter in fields from Jira extension
We have installed the Jira extension so we can maken Jira issues from Zoho desk. In Zoho desk I can also see the Jira issue status for example but I can not filter on this field. I would like to setup an filter showing me the closed Jira issues. How can
Zoho Creator customer portal limitation | Zoho One
I'm asking you all for any feedback as to the logic or reasoning behind drastically limiting portal users when Zoho already meters based on number of records. I'm a single-seat, Zoho One Enterprise license holder. If my portal users are going to add records, wouldn't that increase revenue for Zoho as that is how Creator is monetized? Why limit my customer portal to only THREE external users when more users would equate to more records being entered into the database?!? (See help ticket reply below.)
Link Contacts to Billed Accounts
Hello, I want to do a survey on all my customers of 2025. For that I want to select all contacts linked to accounts who where billed in 2025. How to I create this link to I can then use Zoho Survey with this database of contacts?
Pre-Zoho Sales Info - Best Way to Add to Desk / CRM
My company has been using Zoho One since 2021, with sales data going back through 2020. However, we have been in business much longer, and we have historical sales information that we want to have at our fingertips when talking with customers (usually
CRM function REST API response format
Is there a way to control the JSON response returned by the CRM function REST API? If I call a function using either OAuth or an API key it returns a 200 OK response with a string in the format shown below. I am using a particular feature of an external
Unable to Access Application:
Whenever I try to access my application from the desktop, say I am editing it and want to test something in the desktop environment I get: An error has occurred. An internal error has occurred. Please check the URL , or try refreshing the page I can edit
Cannot see Application from Lookup field
Hi all, I am trying to access data for an application on our account via a lookup field; however, the application doesn't appear in the dropdown at all. Can anyone shed any light on this, please? I have asked Zoho support; however, they're just as confused,
Zoho CRM Meetings Module Issues
We have a use-case that is very common in today's world, but won't work in Zoho CRM. We have an SDR (Sales Development Rep) who makes many calls per day to Leads and Contacts, and schedules meetings for our primary Sales Reps. He does this by logging
Next Page