pepkad
(Daniel)
November 6, 2019, 11:31pm
1
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
tommy
(Tommy Gaessler)
November 7, 2019, 6:38am
2
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
pepkad
(Daniel)
November 7, 2019, 7:04pm
3
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)
pepkad
(Daniel)
November 7, 2019, 7:06pm
4
What results is a webpage that had an iframe in it hosting a zoom player.
pepkad
(Daniel)
November 7, 2019, 7:10pm
5
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 )
pepkad
(Daniel)
November 7, 2019, 7:12pm
6
After modifying the ZoomMeeting.cshtml page you can rebuild / run and instead you get this page which works and connects to the meeting.
tommy
(Tommy Gaessler)
November 7, 2019, 8:43pm
7
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?
Timezone = "America/Los_Angeles",
Password = "",
Agenda = "What is an agenda?",
Recurrence = null,
Settings = new AndcultureCode.ZoomClient.Models.Meetings.MeetingSettings() { EnableJoinBeforeHost = true }
});
request.MeetingNumber = meeting.Id;
}
string meetingNumber = request.MeetingNumber;
string ts = ToTimestamp(DateTime.UtcNow.ToUniversalTime()).ToString();
string role = "0";
string token = GenerateToken(options.ZoomApiKey, options.ZoomApiSecret, meetingNumber, ts, role);
output.ZoomToken = token;
output.MeetingNumber = request.MeetingNumber;
output.ApiSecret = options.ZoomApiSecret;
output.ApiKey = options.ZoomApiKey;
return output;
Agenda = "What is an agenda?",
Recurrence = null,
Settings = new AndcultureCode.ZoomClient.Models.Meetings.MeetingSettings() { EnableJoinBeforeHost = true }
});
request.MeetingNumber = meeting.Id;
}
string meetingNumber = request.MeetingNumber;
string ts = ToTimestamp(DateTime.UtcNow.ToUniversalTime()).ToString();
string role = "0";
string token = GenerateToken(options.ZoomApiKey, options.ZoomApiSecret, meetingNumber, ts, role);
output.ZoomToken = token;
output.MeetingNumber = request.MeetingNumber;
output.ApiSecret = options.ZoomApiSecret;
output.ApiKey = options.ZoomApiKey;
return output;
}
}
Thanks,
Tommy
pepkad
(Daniel)
November 7, 2019, 9:04pm
8
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.
pepkad
(Daniel)
November 7, 2019, 9:04pm
9
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.
pepkad
(Daniel)
November 7, 2019, 9:06pm
10
I could private message you the api key / secret if that would help.
tommy
(Tommy Gaessler)
November 7, 2019, 9:16pm
11
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
pepkad
(Daniel)
November 7, 2019, 9:29pm
12
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.
pepkad
(Daniel)
November 7, 2019, 9:41pm
13
I’m trying to join a meeting that I’ve hosted which enables join before host.
tommy
(Tommy Gaessler)
November 7, 2019, 10:00pm
14
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
tommy
(Tommy Gaessler)
November 11, 2019, 5:42pm
16
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