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
customer Name and address details
i created one application there is no customer details in that . how to add customer details and
Recalculate every row in the subform
Hello, Can anyone help me with a script, please? I have an issue. Sometimes it happens, that in a multi row subform one of the rows show an incorrect row total value. Not really understand how it can happen, if I have a 20 row subform, 19 rows show correct
Creating Repeat Forms that remove redundancies
I wanted to understand if you can make multi-layer forms that reduce the need for users to input information in again and again. We want a form that our suppliers fill out per ingredient they sell, and the end result should have the Ingredient (Section
What is the difference between the free plan and the mail lite plan?
What is the difference between the free plan and the mail lite plan? How many emails can I send per day?
Unblock email
Hi The outgoing mail from a client of me is blocked. I already made tickets and tickets are send to the EU desk but nobody is responding. The problem is already 4 days! There is absolutely no help from the support. I am really not satisfied at all! Can
Domain verification failure
Hello Zoho Support, I purchased my domain directly through Zoho Mail, but the domain verification keeps failing with the message “TXT verification failed.” I’ve already waited and retried several times, but it still won’t verify. Could you please manually
Unable to send message;Reason:554 5.1.8 Email Outgoing Blocked.
My email account is unable to send emails, and I urgently need to use it. How can I resolve this?If there is anything we have done wrong, please let us know in advance so we can actively cooperate to improve. User ID: 850482493
URGENT: Email stopped workin - can't access admin panel
For some reason email sending stopped working. When I try to send an email it fails with "Unable to send message;Reason:451 4.7.1 Temporary system error" I can receive email just fine I see in my notifications some errors about the MX records, however
Can I associate an invoice to a Project after the fact?
We have generated an invoice but would like to assoicate it to a Zoho Project after the fact. Is there any way to accomplish that? Thanks, Scott
Emails I send as a cc or bcc NEVER GO THROUGH TO THA RECEIVER !!
every time i send a cc or bcc copy of an email to anyone when I’m using my zohomail.com email - no one ever gets the cc of bcc copy if the email: why???? And i triple check that the email addresses are correct; then i get back an email message (EVERYTIME)
Cannot see correct DNS config for mail after moving domain to another provider
I have moved my domain from one provider to another and after that zoho mail stopped working (expected). Problem is, zoho mail admin panel still shows (10 hours after move) that all records are correct while I haven't changed anything in my domain DNS
Add Support for Authenticator App MFA in Zoho Desk Help Center
Hello Zoho Desk Team, We hope you are doing well. We would like to request an enhancement related to security for the Zoho Desk Help Center (customer portal). Currently, the Help Center supports MFA for portal users via SAML, JWT, SMS authentication,
Auto-fill Contacts in Zoho Mail not working for me
We just switched to Zoho Mail for our company, and I am noticing that the "auto fill" feature when composing an email -- where the "to" field is autofilled (like in the attachment) from Contatcts works for everyone except me. Any way I might have made
How to unlink a SAML user from the existing Zoho Desk user (domain change case)
Hi everyone, I’m trying to understand how to handle a situation where a customer changes their company domain. In our setup, users authenticate via SAML, so when the domain changes, the SAML system treats them as a new user. However, in Zoho Desk, I’d
Price Managment
I have been in discussions with Zoho for some time and not getting what I need. Maybe someone can help explain the logic behind this for me as I fail to understand. When creating an item, you input a sales rate and purchase rate. These rates are just
Related to zoho survey
Hi team. I want to know something regarding zoho survey question builder. I have two questions each of dropdown (One answer) - question type. In the first question, there are 16 answer choices and in the second question, there are 3 answer choices. For
Text Message
When trying to sent a text message, it says its an error i should contact a zoho agent
Zoho POS is now available for Canadian retailers
Hey everyone, We're excited to introduce the all-new Canadian edition of Zoho POS, which helps retail businesses simplify and manage their end-to-end business operations. Start by signing up and exploring the 15-day free trial. Sign up now How does Zoho
Payroll In Canada
Hi, When can we expect to have payroll in Canada with books
Mass update to change or shift all project dates and keep project structure + shift all sub-tasks dates with main tasks
Most users would expect that if they change the start date of their project then that will be reflected inside the actual project and any project structure would be retained. Additionally if a task list with associated sub-tasks is moved, most users would expect that those sub-tasks would also be moved along with their parent task. This is not the case. For a total Project shift of dates: * the start and end date from > "Edit Project" page can have a radio button added to "shift all project tasks
Closing Accounting Periods - Invoice/Posting dates
Hi, I have seen in another thread but I'm unsure on how the 'transaction locking' works with regards to new and old transactions. When producing monthly accounts if I close December 24 accounts on 8th Jan 25 will transaction locking prevent me from posting
In-person ZUG Meetups for Real Estate Professionals - US Q1 2026
The Real Estate Zoho User Group is going on a multi-city, in-person meetup tour across the US, and we’d love to see you there! These meetups are a great opportunity to: Connect with fellow real estate professionals using Zoho Share challenges and discover
Zoho CRM custom fields not showing in zoho creator
Hi Team, I have created a Products form with Zoho CRM integration and connected it to Products module of CRM. But when I see the reports of Products in Zoho creator then I am not able to see custom fields of Products module. Only standard fields of Products
Sending email notifications based on language
Hello. I would like to know how we can bypass the default notifications (which are just in English) for when a ticket is created/replied to/closed, to be in other languages, based on the language field in the ticket? I can create other email templates,
Zoho Error: This Operation has been restricted. Please contact support-as@zohocorp.com for further details
Hello There, l tried to verify my domain (florindagoreti.com.br) and its shows this error: This Operation has been restricted. Please contact support-as@zohocorp.com for further details. Screenshot Given Below - please check what went wrong. Thanks
Download a file from within a zoho creator widget
I have a widget running in Zoho Creator , it displays uploaded documents in a table file, and I have added a download link in the view. ( The widget is created with html, css and javascript). I do not succeed in getting the download working. Do I have
Zoho / Outlook Calendar sync
The current Marketplace -> Microsoft -> Meetings integration needs 2 changes. 1. The current language for the Two-Way sync option should be changed. It currently states, "Sync both your Zoho CRM Calendar and Office 365 Calendar meetings with each other."
Email content just contain 'OK' ,not what we expect
create campaign API URL: https://campaigns.zoho.com/api/v1.1/createCampaign req params: {'campaignname': 'General_Outreach_d0cfc415-43aa-4b96-bb09-558e76a3dda3_50_20251117_214806_660', 'from_email': 'admin@allinmedia.ai', 'subject': 'ALL IN MEDIA', 'list_details':
Reopen ticket
Hello! Can I reopen a ticket just using the API ticket/sendReply ? What's the rules to do it? I'm trying but it doesn't reopen the ticket, it just send the reply
Allow Admins to Transfer Ownership of Their Own Files & Folders
Hi Zoho WorkDrive Team, Hope you are doing well. We would like to request an important enhancement to the ownership-transfer functionality in Zoho WorkDrive, specifically regarding administrator capabilities. As administrators, we have the ability to
Tip#46: Capture accurate log hours
Hello everyone, Use the newly introduced timer settings that will streamline the usage of timers and help admins or workspace owners to manage the time entries of the workspace users better. Check out the below mentioned timer settings added to the Timesheet
Moving to app-specific authentication for Google integrations
Hello everyone, We’re making an important change to how Google integrations work in our platform. Until now, we used a common Google project across Zoho to enable integrations like Google Drive, Calendar, and more. Going forward, we’ll be moving to an
Lost the ability to sort by ticket owner
Hi all, in the last week or so, we have lost the ability to sort tickets by Ticket Owner. Unlike the other columns which we can hover over and click on to sort, Ticket Owner is no longer clickable. Is it just us, or are other customers seeing this too?
How Can i put a form in Zobot
Hi,how can i integrate a form which has a multiple options to choose from.the form should be opened or displayed by zobot after it meets a requirement in the conversation. Thanks in advance !
Playback and Management Enhancements for Zoho Quartz Recordings
Hello Zoho Team, We hope you're all doing well. We would like to submit a feature request related to Zoho Quartz, the tool used to record and share browser sessions with Zoho Support. 🎯 Current Functionality As of now, Zoho Quartz allows users to record
Zoho Analytics - Feature Request For Time Based Data Source Fetch
Hi Analytics Team, I have a client using Zoho CRM and they want a weekly report at 4:30pm every Friday, emailed to the sales team showing a pie chart of Closed Won Deals for that week. This is easy to achieve in Analytics but not so easy to ensure the
Which user's capacity is used for Shared Mailbox storage?
We use shared mailboxes at our company, and their size is increasing daily. Which user(s)'s total mailbox limit is being used up by this space?
Inserting the current date / time
I'd like to use Zoho Notebook as a log - so it would be great to be able to insert the current date and time at the beginning (or end) of each my log/journal entries - or wherever I want. Something simple, like pressing a button/icon to insert it wherever my text cursor is. It could be formatted like "Mon Dec 11, 2017 - 11:43p".
Campaign editor overrides href value
I've been trying to insert a deep link in an email campaign so recipients can directly open a native app on their device. My deep link looks something like "myapp://". The options to insert links in the campaign editor are limited to strict urls, emails,
Bug Report and Suggestions for Improvement in Zoho Applications
Hi Zoho Team, I’d like to report a few bugs and improvement suggestions I’ve noticed while using Zoho products: Zoho Cliq Video Call: The camera sometimes turns off automatically during video calls. This seems to be a bug — please check and fix it. Zoho
Next Page