Description I’m trying to create meeting by using Zoom meeting Apis After getting an access token by using grant type of client_credentials and using client id and client secret of server-to-server oauth app type. By this way I got an access token
“But when trying to use this access token at create meeting api I got the error message the mentioned below”
Error? Invalid api key or secret.
How To Reproduce Steps to reproduce the behavior: 1. https://api.zoom.us/v2/users/{my-user-id}/meetings 2. client credentials and server to server oauth app type 3. {
“code”: 200,
“message”: “Invalid api key or secret.”
}
Hope you are doing great! I am happy to help here!
This looks like a credentials issue.
Please refer to the following thread were I helped other developers with a similar issue:
Thanks for your help, that URL fixes my issue.
But I have another issue when trying to join meeting through Meeting Web SDK, Using sdk jwt type.
After generating SDK JWT token as a signature(by using SDK key and SDK secret that generated from SDK type app ) and pass this signature to join meeting function with the other parameters, I got this error( errorCode: 3712, errorMessage: “Signature is invalid.”, method: “join”, result: “Invalid signature.”, status: false ).
Have you tried to generate the signature with our sample? I’ve found manually entering the output from our sample app, then comparing signatures helps isloate the root cause.
Hello again,
I can confirm from the sample above that I have something wrong in my signature. But I really cannot figure it out.
This signature is generated with my code:
[REDACTED]
And this one is generated with the sample:
[REDACTED]
both signatures are for the same meeting number.
The generated tokens are so close even in time but the one from the sample is working and the one generated with my app is not working and getting me Invalid Signature error!
I don’t know where the problem is.
I’m using C# and JwtSecurityTokenHandler
and creating the token as follows:
meetingNumber = "xxxxxxxxxx";
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("sdkKey", sdkKey),
new Claim("mn", meetingNumber),
new Claim("role", role),
new Claim("iat", ts.ToString()),
new Claim("exp", expTs.ToString()),
new Claim("appKey", sdkKey),
new Claim("tokenExp", expTs.ToString())
}),
//Expires = now.AddMinutes(Convert.ToInt32(120)),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey),SecurityAlgorithms.HmacSha256Signature)
};
var stoken = tokenHandler.CreateToken(tokenDescriptor);
@xpe ,
It looks like the iat value is invalid. You can use https://jwt.io/ to decode your token and verify the values for the payload properties are correct:
Thanks for your replay.
The invalid date is appearing just because of the double quotes. Actually, the value you are referring to, is in the working signature.
I tried by both, the double quotes and without but the result is the same.
After investigation, I can confirm that the problem is in the way I’m using the signature.
I’m revising it. appreciate if there is any updated code that is in c# or .Net for SDK signature generation.
I was able to find the solution for the problem.
I was treating apiSecret as base64 string and converting it to byte using: var symmetricKey = Convert.FromBase64String(apiSecret);
And this was the issue.
Using ASCII encoding instead solved the problem: var symmetricKey = Encoding.ASCII.GetBytes(apiSecret);
Awesome to hear you were able to resolve the issue, @xpe! I will make sure to get this caveat documented and will share it here. In the meantime, can you share the entire code snippet of the working solution for other community members’ benefit?
Here is a complete signature generation code using c# and System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler
hopefully it would help others:
public string GenerateSdkJwtToken(string apiKey, string apiSecret, string meetingNumber, int role)
{
//convert secret to byte[]. This is the correct way.
var symmetricKey = Encoding.ASCII.GetBytes(apiSecret);
var tokenHandler = new JwtSecurityTokenHandler();
//don't automatically add nbf to the generated token.
tokenHandler.SetDefaultTimesOnTokenCreation = false;
//set issue date and expiration.
var now = DateTime.UtcNow;
//get epoch seconds.
long tss = ToTimestamp(now.ToUniversalTime()) - 30;
long expTs = tss + 60 * 60 * 2; //add a reasonable value for expiration time.
//token payload
var objTokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("sdkKey", sdkKey),
new Claim("mn", meetingNumber),
new Claim("role", role.ToString()),
new Claim("iat", tss.ToString()),
new Claim("exp", expTs.ToString()),
new Claim("appKey", sdkKey),
new Claim("tokenExp", expTs.ToString())
}),
//sign the token using Sha256
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey),SecurityAlgorithms.HmacSha256Signature)
};
var sTokenObj = tokenHandler.CreateToken(objTokenDescriptor );
var strJwtToken = tokenHandler.WriteToken(sTokenObj);
//here is your final token.
return strJwtToken;
}
//There are several way you can get Epoch seconds. Here is one method
public static long ToTimestamp(DateTime value)
{
TimeSpan t = value - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long secondsSinceEpoch = (int)t.TotalSeconds;
return secondsSinceEpoch;
}