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
Empowered Custom Views: Cross-Module Criteria Now Supported in Zoho CRM
Hello everyone, We’re excited to introduce cross-module criteria support in custom views! Custom views provide personalized perspectives on your data and that you can save for future use. You can share these views with all users or specific individuals
Associating a Candidate to a Job Listing
Hello, I am trying to use Zoho Forms embedded on my website for candidates to apply for a job opening. I want the form then to tie directly with zoho recruit and have the candidate be automatically inputed into Recruit as well as associated with the specific
WhatsApp Voice Message Sending Option in Bigin CRM
I would like to request a feature that allows users to send WhatsApp voice messages directly from Bigin CRM. This would help improve communication efficiency and make it easier for teams to respond quickly to customer inquiries.
CRM: hosting a single html file in Zoho and displaying it as a widget
I have seen that CRM offers the option of uploading a web project to Zoho itself and displaying it as a widget in CRM. The instructions then talk about setting a development environment with Node and developing an application to upload to Zoho. But I
How to change position button transtition of Blueprint?
Hi Everyone, Look at my screenshoot, it is possible move the reject button to the right? I couldn't find that setting in the blueprint. Thank you.
Multi file upload
Hi, I just wonder if one could upload multiple files in one shot, say between one and three files, without adding multiple File Upload fields? Thanks, Alalbany
Sorting Descending in a lookup
I have a case number lookup on multiple forms. I need the most recent added to appear at the top of the lookup or as the list of cases grom it's too much to scroll. Is there a way to have a look up sort descending?
Auto-upload Creator Files to WorkDrive
Hi everyone, I’m working on a workflow that uploads files from Zoho Creator to specific subfolders in Zoho WorkDrive, as illustrated in the attached diagram. My Creator application form has two multi-file upload fields, and I want—on successful form submission—to
Asap Widget 2.0
Where's the documentation for the new ASAP widget? https://www.zoho.com/desk/developers/asap/#introduction this one is outdated How can we dynamically navigate between different views? How can we prefill ticket forms using ASAP 2.0?
Can the Trigger be changed?
I'm afraid I already know the answer, but here goes... After activating a workflow (under Campaigns > Automations), Then later choosing to Edit the workflow, Can the Workflow's Trigger be changed? Currently the entire Trigger section + options are gone
Marketer's Space: Proven tips to improve open rates – Part I
Hello Marketers! Welcome back to another post in Marketer's Space! In this week's post, we'll discuss the ever-important concept of open rates. This will be a multi-part series, as we have a range of topics to cover. Open rates—which measure the percentage
Can't send nor receive emails on my external email accounts since this morning
Greetings, I have two external accounts integrated into Zoho mail through POP3 + SMTP. These accounts have always worked normally since the day I've set them up. Starting 10:30 AM this morning (Western European Time) both suddenly stopped sending and
Creating Custom PDF Template from Form
I am trying to create a custom PDF from form submissions. I have the standard subscription and it indicates that PDF forms are included. I cannot find anywhere to create PDF forms. I try to follow the instructions from here: https://help.zoho.com/portal/en/kb/forms/form-settings/pdf-settings/pdf-editor/articles/creating-your-own-pdf-template#Creating_your_template_from_the_scratch
Cannot connect to imap.zoho.eu on iOS26
Hey, I recently migrated to another iPhone and since then use iOS26. Every since then, I was not able to connect to "imap.zoho.eu" from Apple Mail. I tried deleting the account and adding it again, did not work. I tried creating an app password, didn't
Important Update: Facebook Metrics Deprecation & Impact on Zoho Analytics
Dear Zoho Analytics users, Facebook has deprecated a set of metrics from the Facebook Pages Insights API, effective November 15, 2025. As a result, these changes will affect any reports and dashboards in Zoho Analytics that rely on Facebook Pages data.
Quick Copy Column Name
Please add the ability to quickly copy the name of a column in a Table or Query View. When you right-click the column there should be an option to copy the name, or if you left-click the column and use the Ctrl+C keyboard shortcut it should copy the
Conditional Field Visibility in Bigin CRM
I would like to request support for conditional field visibility within Bigin CRM. This feature should allow administrators to configure show/hide rules for fields based on predefined criteria (e.g., field values, picklist selections, stage changes,
Introducing Zoho MCP for Bigin
Hello Biginners! We're excited to introduce Zoho MCP for Bigin, a completely new way of interacting with Bigin data using AI. With Zoho MCP, you can securely connect your Bigin account with popular AI agents like Claude, Cursor, Windsurf, and VS Code,
MCP > Creator connection failing with Claude
I'm trying to get claude to access any of my Zoho Creator apps and it keeps failing. I have enabled all tools for creator and ensured in claude settings that everything is authorised. Here is what claude says : Unfortunately, the error messages I'm receiving
Is it possible to sync data every 5–10 minutes in Zoho Analytics (CRM or Excel imports)?
Hello Team, I want to know if Zoho Analytics supports near real-time syncing of data from different sources. My requirements: I am importing data from Zoho CRM → Zoho Analytics I also have some datasets maintained in Excel/CSV I want both data sources
Feature Request: Dynamic Dimension Control for zc_LoadIn Popups
As detailed in this community discussion, Zoho Creator's zc_LoadIn parameter is a vital tool for opening components (forms, reports, or pages) in modal dialogs via HTML snippets, Notes, or Rich Text Fields. While powerful, this feature suffers from a
Subforms in stateless forms
I think the title says it all. We need to be able to add subforms to stateless forms. Currently the only workaround is to create a Form and delete each record upon submission of the form. I need to build an interface to update our inventory. Basically
Text wrap column headers in reports?
Is it possible to auto wrap column headers so that a longer multi-word header displays as two lines when the column is narrower than the width of the header title?
Request to Permanently Delete Email User (info@mehboobgulf.com ) from Old Organization
“Please permanently delete the user email info@mehboobgulf.com It is still associated with my old Zoho organization. I cannot delete it because it shows ‘You cannot delete email. Zoho host’. I need to use this email in a new Zoho account.” I shell very
Request to Permanently Delete Email User (info@mehbobgulf.com ) from Old Organization
Please permanently delete the user email info@mehbobgulf.com It is still associated with my old Zoho organization. I cannot delete it because it shows ‘You cannot delete email. Zoho host’. I need to use this email in a new Zoho account.”
What’s New in Zoho Inventory — Latest Features, Integrations & Updates | December 2025
Zoho Inventory has evolved significantly over the past months, bringing you smarter, faster, and more connected tools to streamline your operations. Whether you’re managing multichannel sales, complex fulfillment workflows, or fast-moving stock, our newest
Marketer’s Space - Multi-Channel Campaigns for the Biggest Shopping Week with Zoho Marketing Automation
Hello marketers, Welcome back to another post in Marketers Space! The biggest shopping week of the year is almost here, and it’s your moment to shine without the stress. With Black Friday and Cyber Monday just around the corner, being present across email,
Client host [89.36.170.5] blocked using Spamhaus
Hello please make make actions for delist ..... "Client host [89.36.170.5] blocked using Spamhaus"
Pricing Strategies: #5 Stay local, Price & Sell Global
Arun had always dreamed of taking his handmade craft business beyond his hometown. For years, he sold locally. Most of his customers are familiar faces, in our usual currency and with the exact expectations. But one day, a traveller visited his workshop
What is the easiest way to move Hotmail emails to an IMAP server?
The easiest way to move Hotmail (Outlook.com) emails to an IMAP server is to add your Hotmail account directly to any email client that supports IMAP, then copy the messages across. This avoids paid tools and keeps the process simple. Fastest free method:
No feedback from Zoho Books regarding Yodlee feeds for Investec
I reported on 6 Feb 2025 that the Bank Feeds for Investec bank via Yodlee are not working. To date there has been no resolution. You are charging us for a suite of products where the functionality does not work. Please advise how you will refund me for
Turn off Knowlege Base Follow options and Follower lists
Is there a way to hide or turn off the option in the Knowledge Base for users to follow specific departments/categories/sections/articles? If not, is there a way to turn off the public list of followers for each of those things? Otherwise, customer names
Suggestion: Option to Re-run a migration
As I'm going through a migration process, I like the IMAP migration tool, but it would be better if there were an option to re-run the same migration as configured. There's not even an option to copy/edit one that's already there. Just run if it hasn't
Text snippet
There is a nice feature in Zoho Desk called Text Snippet. It allows you to insert a bit of text anywhere in a reply that you are typing. That would be nice to have that option in Zoho CRM as well when we compose an email. Moderation Update: We agree that
Service One. Bill Another. Zero Hassle.
In field service operations, one challenge often comes up: the person who needs the service isn’t always the one who pays for it. Think about tenants vs. property managers, corporate offices vs. their finance departments, or school buildings vs. central
Presenting ABM for Zoho CRM: Expand and retain your customers with precision
Picture this scenario: You're a growing SaaS company ready to launch a powerful business suite, and are looking to gain traction and momentum. But as a business with a tight budget, you know acquiring new customers is slow, expensive, and often delivers
Can Zoho Flows repeat Actions more than once?
I'm attempting to make an intentional Zoho Flow loop using the below layout. However, when "WithinLimit" condition is met, the program fails to execute the action "Get & Add Request Co..." again. Is this by design? Is Zoho Flows unable to repeat actions
Video interviews not compatible on mobile
Hi Zoho, The 2-way video interview feature you have added to Recruit would be great if the candidate was able to use the link to the video on a mobile phone, it doesn't work on Samsung browser, it doesn't work on chrome/firefox mobile version of browser,
Zoho Desk View Open Tickets and Open Shared Tickets
Hi, I would like to create a custom view so that an agent can view all the open tickets he has access to, including the shared tickets created by a different department. Currently my team has to swich between two views (Open Tickets and Shared Open Tickets).
Enviro Recycling EHF Fee's
I'm in Canada and each province has it's own recycling program with it's own fee's. There are numerous categories that electronics fall into and each category has a taxable rate applied to it. I need a way to be able to apply the correct rate depending
Next Page