# Authorization and deep linking In this section, you'll implement the installation and authorization flows to install a chatbot in a Zoom workspace, authenticate API requests, and deep link users between a browser-based application and the Zoom desktop client. This enables seamless transitions from SaaS web apps to native collaboration environments. By the end of this section, you’ll have: - A secure Chat integration using OAuth 2.0 - Seamless deep linking between the browser and Zoom client - Reusable server endpoints for message delivery and future features --- ## Implement OAuth 2.0 authentication Add two routes to handle the OAuth 2.0 flow: one to initiate login and another to process the callback from Zoom. | Endpoint | Description | | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `/login` | Redirects users to Zoom's OAuth consent screen using the app's client ID and redirect URI | | `/callback` | Handles the redirect from Zoom, validates the state parameter, exchanges the authorization code for an access token, and stores tokens in the session for later use | ### File Path `routes/oauth-routes.js` ### Code Snippet ```javascript import express from "express"; import crypto from "crypto"; import { buildBasicAuth, exchangeCodeForAccessToken, } from "../utils/zoom-api.js"; const router = express.Router(); // OAuth: start router.get("/login", (req, res) => { try { const state = crypto.randomBytes(16).toString("hex"); req.session.oauth_state = state; const url = buildBasicAuth({ clientId: process.env.ZOOM_CLIENT_ID, redirectUri: process.env.ZOOM_REDIRECT_URI, state, }); console.log("Redirecting to Zoom OAuth URL:", url); return res.redirect(url); } catch (e) { console.error("OAuth login error:", e); return res.status(500).send("OAuth not configured."); } }); // OAuth: callback router.get("/callback", async (req, res) => { try { const { code, state, error, error_description } = req.query; if (error) { console.warn("Zoom authorization error:", error, error_description); return res.status(400).send(`Authorization error: ${error}`); } if (!code || !state) return res.status(400).send("Missing code or state."); if (state !== req.session.oauth_state) return res.status(400).send("Invalid state."); delete req.session.oauth_state; // one-time use const tokens = await exchangeCodeForAccessToken({ code, redirectUri: process.env.ZOOM_REDIRECT_URI, clientId: process.env.ZOOM_CLIENT_ID, clientSecret: process.env.ZOOM_CLIENT_SECRET, }); // Demo: store tokens in session (use DB/secret store in prod) req.session.zoomTokens = tokens; // Option A: redirect to a confirmation page with a button to open in Zoom return res.redirect("/dashboard"); // Option B: redirect straight into Zoom via a JID deep link: // return res.redirect(process.env.ROBOT_ZOOM_BOT_JID || '[https://zoom.us/launch/chat?jid=robot_example@xmpp.zoom.us](https://zoom.us/launch/chat?jid=robot_example@xmpp.zoom.us)'); } catch (e) { console.error("OAuth callback error:", e); return res.status(500).send("Token exchange failed."); } }); export default router; ``` ## Add deep linking to the chatbot After the user authorizes your app, use a deep link to open the chatbot directly in Chat. ### File path ```plainText views/dashboard.html ``` ### Code snippet ```HTML ``` > **Transition from browser-based app to Zoom client** > > Use this pattern to create a smooth transition from your browser-based app to the Zoom client, enhancing user experience after authorization.