"Signature is invalid, errorCode: 3172, JOIN_MEETING_FAILED"

Description
I created the Server-to-Server app, and I am trying to use it with React/ZoomMtgEmbedded/@zoom/meetingsdk.
Expectation: For users to join a zoom call using my app, without having to register/log in into Zoom.

Browser Console Error
{type: ‘JOIN_MEETING_FAILED’, reason: ‘Signature is invalid.’, errorCode: 3712}
errorCode: 3712
reason: “Signature is invalid.”
type: “JOIN_MEETING_FAILED”
[[Prototype]]: Object

To Reproduce(If applicable)
Here is what I did so far:

  1. Created the app on marketplace.zoom.us
    Develop > Build Server-to-Server App

  2. Filled in basic info (app name, description …)

  3. In “Scopes”, picked :
    /meeting:read:admin
    /meeting:write:admin
    /whiteboard:read:admin
    /whiteboard:write:admin

  4. Activated the account (got green checkmark and the message “Your app is activated on the account
    Your app is allowed to invoke your selected Zoom APIs”).

So, at this point I have ACCOUNT_ID, CLIENT_ID and CLIENT_SECRET from “App Credentials”, and activated app.

  1. Using Postman made a POST request to " /oauth/token" by sending params:
    grant_type: account_credentials
    account_id: ACCOUNT_ID
    and got the “access_token” in response (as explained in this video tutorial on the Zoom YT channel:
    watch?v=OkBE7CHVzho

  2. Used “access_token” to create the meeting by making POST request to “/v2/users/me/meetings”, where “access_token” is used for authorization (Bearer) as seen in the video mentioned above.

At this point, when I logged into my account, I could see that the meeting was scheduled.

  1. Used meetingsdk-auth-endpoint-sample from zoom’s github
    created the node server for signature creation. Added my CLIENT_ID and CLIENT_SECRET
    Server running on localhost:4000
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const KJUR = require("jsrsasign");

const app = express();
const port = process.env.PORT || 4000;

app.use(bodyParser.json());
app.use(cors());
app.options("*", cors());

const CLIENT_ID = [REDACTED];
const CLIENT_SECRET = [REDACTED];

app.post("/", (req, res) => {
    const iat = Math.round(new Date().getTime() / 1000) - 30;
    const exp = iat + 60 * 60 * 2;

    const oHeader = { alg: "HS256", typ: "JWT" };

    const role = req.body.role;
    const meetingNumber = req.body.meetingNumber;

    const oPayload = {
        sdkKey: CLIENT_ID,
        mn: req.body.meetingNumber,
        role: req.body.role,
        iat: iat,
        exp: exp,
        appKey: CLIENT_ID,
        tokenExp: iat + 60 * 60 * 2,
    };

    const sHeader = JSON.stringify(oHeader);
    const sPayload = JSON.stringify(oPayload);
    const signature = KJUR.jws.JWS.sign(
        "HS256",
        sHeader,
        sPayload,
        CLIENT_SECRET
    );

    res.json({
        signature: signature,
    });
});

app.listen(port, () =>
    console.log(
        `Zoom Meeting SDK Auth Endpoint Sample Node.js listening on port ${port}!`
    )
);

  1. Created React app using vite.
    Installed @zoom/meetingsdk (version: “^3.1.6”)
    Used the example and documentation from meetingsdk-web from zoom’s github
    Here is the created component:
import React from "react";
import "./App.css";

import ZoomMtgEmbedded from "@zoom/meetingsdk/embedded";

const client = ZoomMtgEmbedded.createClient();
let meetingSDKElement = document.getElementById("meetingSDKElement"); // this element added in index.html

const App = () => {
	let authEndpoint = "http://localhost:4000"; // my server
	let sdkKey = [REDACTED];  // CLIENT_ID as instructed in the documentation
	let meetingNumber = "84806506821"; // Meeting number obtained from the response when creating the meeting (STEP 6)
	let passWord = [REDACTED]; // Password obtained in response (STEP 6)
	let role = 0; // Participant role (0 for attendee) - I am trying to join as an attendee
	let userName = "UserNameTest"; 

	client
		.init({
			zoomAppRoot: meetingSDKElement,
			language: "en-US",
			patchJsMedia: true,
		})
		.then(async () => {
			const signature = await getSignatureValue();
			console.log(signature); // signature is received and printed
			if (!signature) {
				throw new Error("Failed to get signature");
			}
			client
				.join({
					sdkKey: sdkKey, // CLIENT_ID
					signature: signature, // Signature obtained from the server (localhost:4000)
					meetingNumber: meetingNumber,
					password: passWord,
					userName: userName,
				})
				.then(() => {
					console.log("joined successfully");
				})
				.catch((error) => {
					console.log(error);
				});
		})
		.catch((error) => {
			console.log(error);
		});
        // passing meetingNumber and role to obtain signature from my server
	async function getSignatureValue() {
		try {
			const response = await fetch(authEndpoint, {
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({
					meetingNumber: meetingNumber,
					role: role,
				}),
			});
			if (!response.ok) {
				throw new Error("Failed to get signature");
			}
			const responseData = await response.json();
			return responseData.signature;
		} catch (error) {
			console.error(error);
			return null;
		}
	}

	return (
		<div className="App">
			<main>           
				<h1>Zoom meeting test</h1>
			</main>
		</div>
	);
};

export default App;

At this point, when I run the app, and try to join a meeting, I can see the zoom video element with a spinner, and after a few seconds a pop-up that says:
“Fail to join meeting. Signature is invalid.”

**Device **
Tried to run on several browsers and 2 different machines (MacOS and Linux machines)

I hope I provided everything that is needed, and I hope someone will be able to help me out. I am not sure if I am doing things the correct way, but I tried to follow the documentation the best I can.
I will stand-by to fill in any additional info that is needed.

Thanks you in advance.

I am facing the exact same issue for the past few days. Weirdly enough, it works with the older credentials that I previously created. However, I tried to create a new app with new credentials to test, but I keep getting the same error about the signature being invalid. I tried every resource available to try to resolve it, but I am still failing to do so.

It was a silly mistake on my part. In the “Embed” section, I had left the meeting SDK untoggled. I assumed that this was only toggled to provide you with the download links of the SDKs. Toggling it resolved my issue.

2 Likes

Hi Noor, thanks for your reply!
Can you help me out just a bit more, I cannot find where is this setting that you talk about. I looked in the “Manage” section on the marketplace, and I cannot find it anywhere.

You need to navigate to your application under “Created Apps” after you click “Manage” . Under “Features” select “Embed” and toggle “Meeting SDK Embed Meeting SDK and bring Zoom features to your app.”

1 Like

Thanks for the quick response. I created the app by going to Marketplace > Develop > Build server-to-server app, and when I create app that way, I do not have the Embed option in Features.
Now I realized that creating the app using “Build Legacy App” and selecting the “Server-to-server app” will give me same options as selecting the “Build Server-to-Server” app, so I guess the server-to-server option is also “legacy way”.
I thought it was not, because of the way it was presented in the “Develop” menu in the marketplace. Also, the documentation is saying that I should use “Build Server-to-Server” app, which is really confusing.
I will now try to do it by “Build App” option, but I am not sure if I should do that, because of the documentation.

Some clarification from Zoom would sure help.

If you know, please tell me, should I use “Create app” option, or “Create server-to-server” option?

Thank you again Noor!

1 Like

@chunsiong.zoom
Could you please take a quick look at the issue I’m facing? Your expertise would be invaluable. Thanks in advance for your help—I really appreciate it!

@Shen ,

For the Client_ID and Client_Secret here, you need to use a the keys from either

  • Meeting SDK App or
  • Build App with Embed → Meeting SDK Toggle button turned on.
1 Like

Thank you for your quick response, I will get right on it!
I will keep you posted if I managed to make it work or not.
Thank you once again

Issue solved!
Thank you again, you helped me a lot, now I understand my mistake!

1 Like

@chunsiong.zoom So I’m receiving the same error as @Shen. I have a server to server app setup. I’m using the credentials (client_id) from my server-to-server app on both the backend and frontend when joining the meeting. Should I approach this differently? Maybe use Build Legacy App?

@Shen How did you resolve your issue? Did you use “Build Legacy App”?

For Meeting SDK, you need to use a different set of credentials. Use the ClientID and Client Secret found in either Meeting SDK App (legacy), or General App with Meeting SDK enabled.

That makes sense and it worked! Thanks 4 your help @chunsiong.zoom!