Kaizen #191: Implementing "Login with Zoho" using Python SDK

Kaizen #191: Implementing "Login with Zoho" using Python SDK

      
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:
  1. The app redirects the user to Zoho’s login page.
  2. The user logs in and approves the requested permissions (scopes).
  3. Zoho sends back an authorization code.
  4. The backend exchanges this code for access and refresh tokens.
  5. 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.
This server runs on http://127.0.0.1:8085/ in our example. 

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.

NotesNOTE: 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:
  1. <body onload="getRecords();">
In script.js, getRecords() calls the login() function:
  1. async function getRecords() {
  2.     login();
  3. }
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:
  1.    if parsed_url.path == '/login':
  2.             redirect_url = query_params.get('redirect_url', [''])[0]
  3.             scope = "ZohoCRM.settings.fields.ALL,ZohoCRM.modules.ALL,ZohoCRM.users.READ,ZohoCRM.org.READ"
  4.             url = "https://accounts.zoho.com/oauth/v2/auth?scope=" + scope + "&client_id=" + self.client_id + \
  5.                   "&redirect_uri=" + redirect_url + "&response_type=code&access_type=offline"
  6.             self._set_headers()
  7.             # Send response
  8.             response = {"url": url, "redirect_url": redirect_url}
  9.  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.
  1. const response = await fetch('http://127.0.0.1:8085/login?redirect_url=http://127.0.0.1:5501/redirect.html');
  2. const data = await response.json();
  3. 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:
  1. function setAccessToken() {
  2.     var hashProps = getPropertiesFromURL();
  3.     if (hashProps) {
  4.         for (var key in hashProps) {
  5.             if (hashProps.hasOwnProperty(key)) {
  6.                 localStorage.setItem(key, hashProps[key]);
  7.             }
  8.         }
  9.     }
  10.     setTimeout(function () { window.close(); }, 0);
  11. }

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:
  1. var code = localStorage.getItem("code");
  2. var location = localStorage.getItem("location");
  3. initialize(code, location, data.redirect_url);
  4. .
  5. .
  6. async function initialize(code, location, redirect_url) {
  7.     const response = await fetch('http://127.0.0.1:8085/initialize?code=' + code + '&location=' + location + '&redirect_url=' + redirect_url);
  8. }
In server.py, the /initialize endpoint handles SDK initialization:
  1. elif parsed_url.path == '/initialize':
  2.     code = query_params.get('code', [''])[0]
  3.     location = query_params.get('location', [''])[0]
  4.     redirect_url = query_params.get('redirect_url', [''])[0]
  5.     LeadsRecords().init(self.client_id, code, location, redirect_url)
In record.py, the SDK is initialized and tokens are stored.
  1. token = OAuthToken(client_id=client_id,
  2.                    client_secret=client_secret,
  3.                    grant_token=code,
  4.                    redirect_url=redirect_url)
  5. Initializer.initialize(environment=environment,
  6.                        token=token,
  7.                        logger=logger,
  8.                        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:
  1. 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).
  2. 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:

    • Sticky Posts

    • Kaizen #198: Using Client Script for Custom Validation in Blueprint

      Nearing 200th Kaizen Post – 1 More to the Big Two-Oh-Oh! Do you have any questions, suggestions, or topics you would like us to cover in future posts? Your insights and suggestions help us shape future content and make this series better for everyone.
    • Kaizen #226: Using ZRC in Client Script

      Hello everyone! Welcome to another week of Kaizen. In today's post, lets see what is ZRC (Zoho Request Client) and how we can use ZRC methods in Client Script to get inputs from a Salesperson and update the Lead status with a single button click. In this
    • Kaizen #222 - Client Script Support for Notes Related List

      Hello everyone! Welcome to another week of Kaizen. The final Kaizen post of the year 2025 is here! With the new Client Script support for the Notes Related List, you can validate, enrich, and manage notes across modules. In this post, we’ll explore how
    • Kaizen #217 - Actions APIs : Tasks

      Welcome to another week of Kaizen! In last week's post we discussed Email Notifications APIs which act as the link between your Workflow automations and you. We have discussed how Zylker Cloud Services uses Email Notifications API in their custom dashboard.
    • Kaizen #216 - Actions APIs : Email Notifications

      Welcome to another week of Kaizen! For the last three weeks, we have been discussing Zylker's workflows. We successfully updated a dormant workflow, built a new one from the ground up and more. But our work is not finished—these automated processes are
      • Recent Topics

      • How to see Statement Details Shown in Unclassified Transactions in All Transactions?

        All, The list of Unclassified Transactions show the Statement Details and Descriptions. What is the method to see that column in the All Transactions list? -Thanks!
      • Zoho Books | Product updates | October 2025

        Hello users, We’ve rolled out new features and enhancements in Zoho Books. From iOS 26 updates to viewing reports as charts, explore the updates designed to enhance your bookkeeping experience. Zoho Books Updates for Apple Devices At WWDC 2025, Apple
      • Bill sent for Payment Approval

        Zoho Books currently supports three levels of transaction approval for bills: Draft, Submit, and Approved. We are looking to add a layer of approval like a bill marked for payment before initiating payment requests through HSBC Bank. Can you please guide
      • Ask the Experts - Live Q&A webinar

        Hello Community, We’re excited to host our very first Ask the Experts session! Join us on 7 April 2026 from 11 a.m. to 12 p.m. (IST) for this live webinar Q&A session, where you will have an opportunity to connect directly with our product experts, gain
      • All new Address Field in Zoho CRM: maintain structured and accurate address inputs

        Availability Update: 29 September 2025: It's currently available for all new sign-ups and for existing Zoho CRM orgs which are in the Professional edition exclusively for IN DC users. 2 March 2026: Available to users in all DCs except US and EU DC. 24
      • Kaizen #235 - Automating record restoration using Recycle Bin APIs in Zoho CRM

        Welcome to another Kaizen week. Here's a question that came up in our developer forum: "I'm working on a piece of software to automate conversion of Leads into Deals based on order status from my company's website. There are some cases where a previously
      • Open PDFs using Zoho PDF Editor

        Hello users, In this article, we will be exploring the open PDF capability in Zoho PDF Editor to collaboratively edit PDFs, insert text and images, add fillable and e-signature fields, and more. You can upload PDFs upto 50 MB or 150 pages. Password-protected
      • One Contact with Multiple Accounts with Portal enabled

        I have a contact that manages different accounts, so he needs to see the invoices of all the companies he manage in Portal but I found it not possible.. any idea? I tried to set different customers with the same email contact with the portal enabled and
      • Bank Feeds Breaking Constantly

        Hey Everyone, I have already reached out to support about this issue but I am wondering if anyone else is having the same issue. My bank feeds keep breaking within days of me fixing them by updating the credentials. Its been happening for a while and
      • Print Sales Orders, Purchase Orders or Invoices from API

        Hello, Is it possible to use the print option that is available in Sales Orders Purchase Orders and Invoices with the API?. I don't see any information in the docs about this. Thanks
      • Timed addition to segments

        Hi there - hoping you can help me figure out a graceful way of doing this: • I want to add contacts to a Segment in Campaigns based on a Stage pick-list field value X in CRM - that bit's fine. The problem is that I only want to add them to the Segment
      • Zoho Developer AI Agent = Claude AI + MCP Server + Zoho Ecosystem

        Hello Zoho Community 👋 I’m excited to share a recent integration we’ve worked on at Officehub Tech: ✅Claude + MCP Server + Zoho Creator Zoho Developer AI Agent – an AI-powered Zoho automation platform This solution connects Zoho applications with an
      • Dynamic Questions in Zoho Forms

        Is it possible to add dynamic questions (like displaying a user’s name) in Zoho Forms? I know this is possible in surveys, but can we implement similar functionality in Zoho Forms?
      • Cliq iOS can't see shared screen

        Hello, I had this morning a video call with a colleague. She is using Cliq Desktop MacOS and wanted to share her screen with me. I'm on iPad. I noticed, while she shared her screen, I could only see her video, but not the shared screen... Does Cliq iOS is able to display shared screen, or is it somewhere else to be found ? Regards
      • Google Fonts Integration in Pagesense Popup Editor

        Hello Zoho Pagesense Team, We hope you're doing well. We’d like to submit a feature request to enhance Zoho Pagesense’s popup editor with Google Fonts support. Current Limitation: Currently, Pagesense offers a limited set of default fonts. Google Fonts
      • CRM

        How do I build an email funnel of 10 emails with decision tree ie; if yes use this email if no use this email. Also I cannot figure out how to add more groups or see my whole groups. I've set up different groups like attorneys is one group of companies/people
      • WebDAV support

        I need WebDAV support so that I can upload/download (and modify) documents from my local file system. Is anything planned in his direction?
      • Replying from same domain as a catch-all?

        I have 2 domains setup on Zoho, both with associated email addresses. They look something like this: john@example.com (primary address) john@test.com (this domain also has a catch-all setup) I use the catch-all for test.com as a public-facing email address
      • Is there a way to show contact emails in the Account?

        I know I can see the emails I have sent and received on a Contact detail view, but I want to be able to see all the emails that have been sent and received between all an Accounts Contacts on the Account Detail view. That way when I see the Account detail
      • Internal Fillable Contract with Zoho Writer (Before Sending to Client)

        Hi everyone, I’m trying to automate the following process in Zoho CRM and would appreciate some guidance. Process: When a Deal moves to a specific stage, CRM triggers an automation. CRM sends a contract template to an internal team member so they can
      • Standard practice rerun updated deluge function over existing recordes

        Hi folks, we have a function which is triggered via webhook from a third-party solution which then calls another api with a contact-id and gets a json payload back and then parses that data to custom fields in our CRM to the record id. As requirements
      • can change deal colors in bigin?

        can be super useful if we can change colors deals process  any way to do it?
      • Import Quote from CRM into document in Writer?

        Hi, I created a quote for a proposal in the Zoho CRM and was wondering if there is a way to embed the quote into a document in Zoho Writer so I can make our sales proposals look a little nicer. Is that possible?
      • Zoho Sheet for Desktop

        Does Zoho plans to develop a Desktop version of Sheet that installs on the computer like was done with Writer?
      • Can I convert MSG to HTML on Mac?

        Yes, you can convert MSG files to HTML on a Mac using software Aryson MSG file Converter. This tool allows you to convert Outlook MSG emails into multiple formats, including HTML, PDF, EML, PST, and more. It preserves all email content, attachments, metadata,
      • Duplicate Leads Notification Help!

        Hello! I have several web forms that have a duplicate lead notification that are being sent to the creator of the web form. I understand how to change the form entry notification, but I am specifically looking to change the recipient of the "Duplicate Lead" notification. Any help you can offer is greatly appreciated! TIA, ~ Jenn
      • Adding Calendar Display to Home Page

        I would like to display my calendar in a module on the Zoho CRM Home Page. I can't figure out a way to do this.  Is it possible to display the CRM Calendar on the Home Page?  
      • Schedule a Call by Date and Time when a specific lead status is selected

        Hi Wanting to create a workflow where a call can be scheduled by date & time when a specific lead status is selected. Can only currently set the date by Due Date - Trigger Date - Plus 'x' day(s) Thanks
      • Incoming email replies not automatically associating with Deals/Opportunities - Is this possible in Zoho CRM?

        Hello Zoho Community, I'm running a travel agency (B2B and B2C) and we've been struggling with what seems like a basic functionality that we cannot get to work properly. Our use case: We send emails to suppliers (hotels, transportation companies) and
      • Duplicate Leads Concerns with Round Robin and Lead Approval Process

        It is great to have the Duplicate Lead Approval Process, there are a few issues with the process that I would greatly appreciate taken consideration in enhancing. It appears that A Lead comes in Lead owner assigned by the Round Robin Check for Duplicate,
      • Private email threads

        When sending a Private email or receiving a response once the email thread has been marked as 'Private'- is there a way to trigger the system to "restart the clock"? I am finding that when someone responds to a 'Private' thread that it is opening the
      • SLA Notification

        Team members have been receiving this notification and feel as though it is as random. Explanation on this notification is appreciated! Also, is there a way to disable this notification?
      • Map: Output None

        Hi, Checking if you help me inspect this block The code below triggers during Successful form Submission from another Form. // rec_a = formA[ID!=0]; rec_b = formB[ID!=0]; ListA = List(); //subformA for each recA in rec_a.ItemSubform { for each recB in
      • Use arbitrary images in deluge

        I am sending emails from my deluge code and I would like to be able to include a few images in the email template. While I know that I could put the on a website somewhere and link to them in the HTML, that is not what I want due to email client security
      • How to add "All Open AND Overdue" back to the Home Page Task Component?

        Hi everyone, I’m looking for a way to restore the Tasks component dropdown list on the Zoho CRM Home Page. Since the recent update to the Task area in my Home Page Classic View, the dropdown options (e.g., My Next 7 Days + Overdue) are too restrictive
      • Sync Attachments in Comments from Zoho Desk to Zoho Projects

        Hello Zoho Desk Team, We hope you're doing well. We are actively using the Zoho Desk–Zoho Projects integration, especially for reporting and managing bugs/issues between support and development teams. Current Limitation: After creating a bugs/issues via
      • Add a way to connect Log360 Cloud logs with Zoho analytics

        Hi, Several month ago Log360 Cloud was added to zoho one - and this is great. But as far as I see there is no prebuilt way to connect Zoho analytics to the logs we have in Log360 Cloud. Please add a prebuilt connection like we have for so many other zoho
      • Auto sync Photo storage

        Hello I am new to Zoho Workdrive and was wondering if the is a way of automatically syncing photos on my Android phone to my workdrive as want to move away from Google? Thanks
      • Funcionalidades y configuration ZohoDesk

        Creo que no estoy sacando el provecho adecuado a la application quisiera solicitar una capacitación al respecto
      • How to call Functions and perform Write Operations using Page Scripts?

        Hi everyone, How to call a function from a Zoho Creator application within a Page Script, also how to perform write operations (adding or updating records) using page scripts?
      • Next Page