Invalid Signature C#

Description/Error
When generating a signature from a .net core 3.0 api server using the c# example from (https://marketplace.zoom.us/docs/sdk/native-sdks/Web-Client-SDK/tutorial/generate-signature) it fails with an invalid signature error.

{method: “join”, status: false, errorCode: 1, errorMessage: “Invalid signature.”, result: null}

C# Code:

Where as using ZoomMtg.generateSignature with the same data works.

var signature = ZoomMtg.generateSignature({
meetingNumber: data.meetingNumber,
apiKey: data.apiKey,
apiSecret: data.apiSecret,
role: meetConfig.Role,
success: function(res){
console.log(res.result);
}
});

I’m really at a loss of where to go from here. Any advice would be appreciated .

Has anyone had any success generating signatures with the C# example? I do not have the ability or desire to deploy a nodejs server just for creating signatures.

Thanks
-Daniel

Hey @pepkad,

Can you post your code here (in text) and steps to reproduce so that I can debug the issue on my end?

Thanks,
Tommy

1 Like

Hi Tommy,

Thanks for the reply, I’ve put my code into a github project. It is a .net core 3.0 server so you must have that installed first. (https://dotnet.microsoft.com/download/dotnet-core/3.0)

First clone the app:

git clone https://github.com/DanielPepka/NetCoreZoomUs

Then modify the zoom controller file to have an api key / secret as well as an email address that is associated with that account. (“TODO - SET THIS”)

From there you can either launch the app with visual studio or through the command line (dot net build / dotnet run)

What results is a webpage that had an iframe in it hosting a zoom player.

If you take the same code, and instead use the same api key / secret to generate the signagure using the ZoomMtg.generateSignature it works.

Modify this page (https://github.com/DanielPepka/NetCoreZoomUs/blob/master/Views/Home/ZoomMeeting.cshtml)

After modifying the ZoomMeeting.cshtml page you can rebuild / run and instead you get this page which works and connects to the meeting.

Hey @pepkad,

Thank you for the detailed response!

May I ask the meetingNumber you are passing in?

Also can you try passing in meetingNumber and role as a Number type and not String type?

Thanks,
Tommy

The meeting Id is generated by the endpoint, but you can also hardcode one by adding it to the meetingConfig. It then passes that id to the controller and skips the meeting creation step.

image

I also modified the role and meeting numbers to be ints instead of a string and it doesn’t change anything. Was a good thought though.

I could private message you the api key / secret if that would help.

Hey @pepkad,

Can you push your changes to github so I can view and test?

Also are you trying to start or join the meeting?

(I don’t need API Key and Secret)

Thanks,
Tommy

Done, I’ve modified the controller and zoommeeting.cshtml file. I added a hardcoded meeting number to a valid meeting on my account, and updated the controller to accept both the role and the meeting number as ints.

I’m trying to join a meeting that I’ve hosted which enables join before host.

image

Hey @pepkad,

Can you send me the signature that is generated from your C# code? Feel free to private message it to me.

Also, can you try updating the Web SDK to the latest version, released a few hours ago 1.6.1.

Thanks,
Tommy

Hey @pepkad,

Please try this code to generate the signature:

// this demo use vscode and .NET Core 2.2.5
// https://docs.microsoft.com/en-us/dotnet/core/tutorials/with-visual-studio-code
// https://dotnet.microsoft.com/download
// dotnet add package Microsoft.IdentityModel.Tokens
// dotnet add package System.IdentityModel.Tokens.Jwt
// https://www.red-gate.com/simple-talk/dotnet/net-development/jwt-authentication-microservices-net/
// https://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/#csharp
// https://marketplace.zoom.us/docs/sdk/native-sdks/Web-Client-SDK/tutorial/generate-signature

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using Microsoft.IdentityModel.Tokens;

namespace Zoom {
    class Program {
        static readonly char[] padding = { '=' };

        static void Main (string[] args) {
            Console.WriteLine ("Zoom copyright!");
            Console.WriteLine ("generate websdk token!");
            string apiKey = "apiKey";
            string apiSecret = "apiSecret";
            string meetingNumber = "";
            String ts = ToTimestamp(DateTime.UtcNow.ToUniversalTime ()).ToString();
            string role = "1";
            string token = GenerateToken (apiKey, apiSecret, meetingNumber, ts, role);
            Console.WriteLine (token);
        }

        public static long ToTimestamp (DateTime value) {
            long epoch = (value.Ticks - 621355968000000000) / 10000;
            return epoch;
        }

        public static string GenerateToken (string apiKey, string apiSecret, string meetingNumber, string ts, string role) {
            string message = String.Format ("{0}{1}{2}{3}", apiKey, meetingNumber, ts, role);
            apiSecret = apiSecret ?? "";
            var encoding = new System.Text.ASCIIEncoding ();
            byte[] keyByte = encoding.GetBytes (apiSecret);
            byte[] messageBytesTest = encoding.GetBytes (message);
            string msgHashPreHmac = System.Convert.ToBase64String (messageBytesTest);
            byte[] messageBytes = encoding.GetBytes (msgHashPreHmac);
            using (var hmacsha256 = new HMACSHA256 (keyByte)) {
                byte[] hashmessage = hmacsha256.ComputeHash (messageBytes);
                string msgHash = System.Convert.ToBase64String (hashmessage);
                string token = String.Format ("{0}.{1}.{2}.{3}.{4}", apiKey, meetingNumber, ts, role, msgHash);
                var tokenBytes = System.Text.Encoding.UTF8.GetBytes (token);
                return System.Convert.ToBase64String (tokenBytes).TrimEnd (padding);
            }
        }

    }
}

Thanks,
Tommy