How to use an On-Behalf Token (OBF) with ZoomSDKJoinMeetingElements for joining meetings hosted by external Zoom accounts?

Description

I am implementing the new On-Behalf Token (OBF) flow for a macOS Meeting SDK application.

Our architecture is:

  • Producer (Host)
  • Talent (Participant)
  • Studio App (Meeting SDK application using Customized UI)

The Studio App joins as a third participant to receive audio/video. After the OBF enforcement, the app can successfully join meetings hosted by the same Zoom account that owns the Marketplace app, but fails to join meetings hosted by any other Zoom account.

I have already implemented OAuth, added the user:read:token scope, and can successfully retrieve an OBF token.

However, I cannot find how to pass the OBF token to the macOS Meeting SDK.

The current documentation references JoinMeetingParam4WithoutLogin.onBehalfToken (Windows/Linux/Web), but the macOS SDK I am using only exposes ZoomSDKJoinMeetingElements, which does not contain an onBehalfToken property.

How should an OBF token be supplied when joining a meeting using the macOS Meeting SDK?

Which macOS Meeting SDK version?

  • 6.5.5 (60068)
  • Also tested with 6.0.2 (33510)

To Reproduce:

  1. Create a Published and Active Meeting SDK application.
  2. Implement OAuth authorization.
  3. Add the user:read:token scope.
  4. Obtain an OAuth access token.
  5. Request an OBF token using:
GET /v2/users/me/token?type=onbehalf

(or /users/{userId}/token?type=onbehalf)

  1. Join a meeting using ZoomSDKJoinMeetingElements.
  2. Observe that:
    • Meetings hosted by the Marketplace app owner’s account join successfully.
    • Meetings hosted by another Zoom account immediately transition through:
Connecting
Failed
Disconnecting
Ended

Additionally, I cannot find any API in the macOS SDK to provide the retrieved OBF token.
**

Logs

  • Result: ZoomSDKError(rawValue: 0) | 0
  • Zoom State ZoomSDKMeetingStatus(rawValue: 1)
  • Zoom Error ZoomSDKMeetingError(rawValue: 101)
  • Zoom Reason: EndMeetingReason(rawValue: 0)
  • Zoom State ZoomSDKMeetingStatus(rawValue: 6)
  • Zoom Error ZoomSDKMeetingError(rawValue: 100)
  • Zoom Reason: EndMeetingReason(rawValue: 0)
  • Zoom State ZoomSDKMeetingStatus(rawValue: 4)
  • Zoom Error ZoomSDKMeetingError(rawValue: 101)
  • Zoom Reason: EndMeetingReason(rawValue: 0)
  • Zoom State ZoomSDKMeetingStatus(rawValue: 7)
  • Zoom Error ZoomSDKMeetingError(rawValue: 101)
  • Zoom Reason: EndMeetingReason(rawValue: 0)

Troubleshooting Routes**

  • Tested with the official macOS Meeting SDK sample application.
  • Tested using the Zoom Test SDK JWT Generator.
  • Verified that SDK authentication succeeds.
  • Verified that joinMeeting() returns ZoomSDKError_Success.
  • Implemented OAuth authorization.
  • Added the user:read:token scope.
  • Successfully retrieved an OBF token from the REST API.
  • Verified the Marketplace app is Published and Active.
  • Tested with both SDK versions 6.5.5 and 6.0.2.
  • Searched the SDK headers for JoinMeetingParam4WithoutLogin, onBehalfToken, and related APIs, but they do not exist.
  • Attempted to use the retrieved OBF token in existing properties such as zak, join_token, and appPrivilegeToken, but the meeting still fails. I understand these may not be the correct properties, which is why I’m asking how OBF should be passed on macOS.

Device

  • Device: Apple MacBook Pro
  • Architecture: Apple Silicon

OS

  • macOS Sequoia

@chan_castingapp there is a onBehalfToken you can include in ZoomSDKJoinMeetingElements Meeting SDK for macOS API Reference: ZoomSDKJoinMeetingElements Class Reference

image

Hi, thanks for your reply.

Could you let me know which macOS Meeting SDK version first introduced support for the onBehalfToken property in ZoomSDKJoinMeetingElements? I couldn’t find it in the SDK versions I tested (6.0.2 and 6.5.5), although it appears in the latest API documentation.

I’m using Xcode 26.3 (Swift 6.2.4). Which macOS Meeting SDK version would you recommend as the most compatible with this Xcode version?

@chan_castingapp it should be there 6.6.10 and above. Transitioning to On Behalf Of (OBF) tokens in Meeting SDK apps - Zoom Developer Blog

Hi @chunsiong.zoom, I was able to resolve the OBF token issue—thank you for your guidance.

I’m now encountering an issue related to my Customized UI implementation not sure if related to the authentication. I’m using a custom video view, and the remote participant’s video sometimes appears as a gray view instead of displaying the live video. The behavior is intermittent and cannot be reproduced consistently.

Some observations:

  • The issue only occurs occasionally.
  • The correct userId is being assigned.
  • createVideoElement() succeeds.
  • The remote user is sending video.
  • When the remote user turns their camera off, their profile picture is displayed correctly.
  • When they turn their camera back on, the video sometimes remains gray instead of displaying the live video.
  • I also tried using ZoomSDKNormalVideoElement instead of ZoomSDKActiveVideoElement, but in that case the gray video issue occurs consistently for the remote participant.

I’m currently using the following implementation:

struct ZoomSDKActiveUserView: NSViewRepresentable {
    @State var userId: UInt32?

    func makeNSView(context: Context) -> some NSView {
        let videoContainer = ZoomSDK.shared().getMeetingService()?.getVideoContainer()

        let activeElement = ZoomSDKActiveVideoElement(
            frame: NSRect(x: 0, y: 0, width: 500, height: 500)
        )

        var videoElement: ZoomSDKVideoElement? = activeElement
        videoContainer?.createVideoElement(&videoElement)

        if let userId {
            activeElement.userid = userId
        }

        return activeElement.videoView ?? NSView()
    }

    func updateNSView(_ nsView: NSViewType, context: Context) {
    }
}

Could you please let me know if I’m using ZoomSDKActiveVideoElement correctly, or if there is a recommended approach for rendering a specific user’s video with Customized UI? Is there anything else I should do after assigning the userId to avoid the intermittent gray video?

Thank you!

@chan_castingapp ZoomSDKActiveVideoElement is meant to follow the active speaker, not display a specific participant by userid.

Use ZoomSDKNormalVideoElement to do that. Add its video view after the meeting is
fully connected, set the participant’s userid, and call subscribeVideo(true).

Make sure the element is retained, re-subscribed when the participant turns
their camera back on, cleaned up properly, and that onSubscribeUserFail is
implemented so you can see whether the SDK is reporting a subscription error.