Suddenly unable to join meetings, then recovered

Meeting SDK Type and Version

We are running a custom client-side integration using the Web SDK, version 2.16.0.

Description

On 2023/10/10 between 1-2 PM (Tokyo, GMT+9), many of our meetings were suddenly not joinable. Before 1 PM, meetings worked exactly as expected. Between 1-2 PM, joining a meeting virtually always failed with “failed to join” errors in the browser log. Sometime towards 2 PM, the exact same meetings suddenly became joinable again.

The code in question was deployed days ago to a staging environment, undergone extensive testing, and has not otherwise been touched since. I also used it that morning to join events successfully, but joining failed in the previously mentioned hours, only to recover functionality, without any action on our part.

Why did our events suddenly become unjoinable, then become joinable again as usual? Should we expect this to happen periodically with the Zoom Meeting API and Web SDK?

Error

The log message in Chrome developer console was just that joining the meeting had failed.

Troubleshooting Routes

  • I checked my internet connection at the time and it was stable. I was also in a non-Zoom video meeting in that time, so it wasn’t intermittently connecting/disconnecting.
  • I checked the Zoom status page but no incidents or service degradation was reported in that time period.
  • I had other users try to join meetings, and they also failed similarly. Everyone was able to join meetings again around the same time afterwards.

Hi @msoliter ,

I don’t see any outages reported. I checked:

I am going to message you for the following to check on our end:

  • account id
  • developer email associated with the Meeting SDK
  • MSDK client id
  • a few meeting ids/uuids where you observed this behavior
  • any other supporting evidence you think might be helpful (i.e. screenshots, screen recording)

Thanks!

I saw your response in the private message. Could you please share the code for how you’re generating your signature? Sometimes we see this issue with iat and token signing.

Sure. I am generating everything on a Go server, then just dumping the JSON as-is into the join method on the frontend.

The code consists of three functions. I fetch the meeting details, specifically the meeting number and password, from the database. These are represented by a Meeting struct. The top-level parameter generation function is as follows:

func (c *zoomClient) generateParams(meeting *Meeting, name string, host bool) (any, error) {
	signature, err := c.generateSignature(meeting.Number, host)

	if err != nil {
		return nil, err
	}

	params := map[string]any{
		"sdkKey":        c.config.AppClientID(),
		"signature":     signature,
		"meetingNumber": meeting.Number,
		"userName":      name,
		"password":      meeting.Password,
	}

	if host {
		zak, err := c.getZak(meeting)

		if err != nil {
			return nil, err
		}

		params["zak"] = zak
	}

	return params, nil
}

A valid signature is generated as follows:

func (c *zoomClient) generateSignature(meetingNumber int64, host bool) (string, error) {
	role := 0

	if host {
		role = 1
	}

	iat := math.Round(float64(time.Now().UnixMilli())/1000) - 30
	exp := iat + 60*60*2
	claims := jwt.MapClaims{
		"appKey":   c.config.AppClientID(),
		"sdkKey":   c.config.AppClientID(),
		"mn":       meetingNumber,
		"role":     role,
		"iat":      iat,
		"exp":      exp,
		"tokenExp": exp,
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	token.Header["alg"] = "HS256"
	token.Header["typ"] = "JWT"
	return token.SignedString([]byte(c.config.AppClientSecret()))
}

Finally, in the case of generating parameters for a host, there’s a routine for fetching the latest zak. The execute function performs the request, does some error checking, and returns a gjson.Result.

func (c *zoomClient) getZak(meeting *Meeting) (string, error) {
	response, err := c.execute(
		"GET",
		fmt.Sprintf("/meetings/%v", meeting.Number),
		nil,
	)

	if err != nil {
		return "", err
	}

	startURL, err := url.Parse(response.Get("start_url").String())

	if err != nil {
		return "", fmt.Errorf("failed to parse Zoom meeting start_url: %v", err)
	}

	query := startURL.Query()

	if !query.Has("zak") {
		return "", fmt.Errorf("start URL did not contains a 'zak': %s", startURL)
	}

	return query.Get("zak"), nil
}

This has worked for joining dozens of test meetings already, and hasn’t failed since the incident on October 10th.

Hi @msoliter ,

I am a bit puzzled here. The code that was deployed to a staging environment – was it different from what you were using before?

Were you able to confirm if your signatures for the meetings between that 1-hr block were valid?

Sorry, this issue resolved itself so I forgot to follow up. The thread you linked has an interesting discussion on how Math.round may have caused the issue. I guess if it happens again that’s where I’ll start.

Glad it’s resolved @msoliter and that the linked thread was helpful :slight_smile: