How to create JWT token using REST api in c#

Hi,

how to create JWT token using REST api in c#

1 Like

Hey @vaibhav.bhosale, thanks for posting and using Zoom!

You can reference our JWT with Zoom guide:

https://marketplace.zoom.us/docs/guides/authorization/jwt/jwt-with-zoom

I would suggest using one of the C# libraries here:

Possible duplicate post with more info:

Thanks,
Tommy

As I recall, you need to create the token on Zoom web-page first. Put some future expiration date, then use that date in the code. You should see the same token during debugging.

Thanks @nvanderson, yes you can do that!

@vaibhav.bhosale, go here: https://marketplace.zoom.us/develop/create, create a JWT app, then on the “App Credentials” page you will see an already generated JWT token:

Thanks,
Tommy

Hi ! I used Microsoft.IdentityModel.Tokens and System.IdentityModel.Tokens.Jwt to create C# command line tool that can generate JWT token for Zoom. In payload you have to use “iss” end “exp”. Sorry, I can’t share my code exactly…

Thanks for posting @lgelman! :slight_smile:

Is the tool you made internal, or do you plan on sharing it?

-Tommy

using System;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
namespace Zoom 
{
    public static class ZoomToken
    {
        public static string ZoomToken(){
		// Token will be good for 20 minutes
        DateTime Expiry = DateTime.UtcNow.AddMinutes(20);

		string ApiKey = "YOUR_API_KEY_HERE");
		string ApiSecret = "YOUR_API_SECRET_HERE";

		int ts = (int)(Expiry - new DateTime(1970, 1, 1)).TotalSeconds;

		// Create Security key  using private key above:
		var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(ApiSecret));

		// length should be >256b
		var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

		//Finally create a Token
		var header = new JwtHeader(credentials);

		//Zoom Required Payload
		var payload = new JwtPayload
		{
			{ "iss", ApiKey},
			{ "exp", ts },
		};

		var secToken = new JwtSecurityToken(header, payload);
		var handler = new JwtSecurityTokenHandler();

		// Token to String so you can use it in your client
		var tokenString = handler.WriteToken(secToken);
		
        return tokenString;
        }
    }
}
6 Likes

Thanks @k.krylov! :slight_smile:

-Tommy

@k.krylov, Thank you!

I created a one-liner to set the expiration date that works for .NET Core 3.1:

var ts = (int)DateTimeOffset.UtcNow.AddMinutes(MINUTES).ToUnixTimeSeconds();

You could replace AddMinutes with a method of your choosing to set the expiration.

1 Like

I think the problem is in the c# example code on zooms site… I took all parameters and compared the output between between the builtin signature function and the output do not match. I am going to need to pull the embeded javascript function apart and replicate in c# unless someone has an uptodate function example.

Thanks for sharing @marklackey! :slight_smile:

-Tommy

Hey @jason3,

Have you tried any of the C# libraries here:

Thanks,
Tommy

This is what works for me on .Net Core 3.1.4
var setting = GetZoomSetting(); //This is where I picked the API Key and API Secret From

        var zone = TimeZoneInfo.FindSystemTimeZoneById("W. Central Africa Standard Time");
        var utcNow = DateTime.UtcNow;
        var westNow = TimeZoneInfo.ConvertTimeFromUtc(utcNow, zone);
        string s = null;
        TimeSpan t = westNow.AddMinutes(Convert.ToInt32(5)) - new DateTime(1970, 1, 1);
        int secondsSinceEpoch = (int)t.TotalSeconds;

        TimeSpan secpacific = TimeZoneInfo.ConvertTimeFromUtc(utcNow, zone) - new DateTime(1970, 1, 1);
        int NowsecondsSinceEpoch = (int)secpacific.TotalSeconds;
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.API.APISecret));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        //Finally create a Token
        var header = new JwtHeader(creds);

        //Zoom Required Payload
        var payload = new JwtPayload
        {
            {"aud",s },
            { "iss", setting.API.APIKey},
            { "exp", secondsSinceEpoch },
            {"iat",NowsecondsSinceEpoch }
        };
        var token = new JwtSecurityToken(header, payload);
        var authtoken = tokenHandler.WriteToken(token);
        return authtoken;
2 Likes

Thanks for sharing your this code snippet @sakosile! :slight_smile:

We appreciate you contributing to the Zoom Developer Community!

-Tommy

Hi, with this code I taking token. But, zoom api return it’s invalid token.
zoom link : https://api.zoom.us/v2/users

Hey @biss.hakanzor,

Are you passing in a JWT token or an OAuth access token as the authorization bearer header?

Thanks,
Tommy

Hi @biss.hakanzor, you’re right. I am also getting the Invalid token when I use @k.krylov 's code.
tommy, I’ve passed the JWT token as authorization bearer header but still no luck. I’ve sent an email to developersupport@zoom.us yesterday regarding the issue and looking for the quicker response because its been a couple days I am stuck in it.

My code has been in production for well over a year, and never experienced any problems. Can you show us the whole thing please

1 Like

Hi @k.krylov,

Here is the sample code(with reference to your code):

private const string apiKey = “MyKey”;
private const string apiSecret = “MyKey”;

public static string ZoomToken()
{
// Token will be good for 20 minutes
DateTime Expiry = DateTime.UtcNow.AddMinutes(20);

int ts = (int)(Expiry - new DateTime(1970, 1, 1)).TotalSeconds;

// Create Security key using private key above:
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(apiSecret));

// I did changes in below line because DLL needed HmacSha256Signature instead of HmacSha256
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

//Finally create a Token
var header = new JwtHeader(credentials);

//Zoom Required Payload
var payload = new JwtPayload
{
{ “iss”, apiKey},
{ “exp”, ts },
};

var secToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();

// Token to String so you can use it in your client
var tokenString = handler.WriteToken(secToken);

return tokenString;
}

And following is the code to call the API:

var jwtToken = ZoomToken();
var client = new RestClient(“https://api.zoom.us/v2/users?page_size=300&status=active”);
var request = new RestRequest(Method.GET);
request.AddHeader(“authorization”, String.Format(“Bearer {0}”, jwtToken));
IRestResponse resp = client.Execute(request);

I think the issue is because of latest DLL version, but I am not sure.
Microsoft.IdentityModel.Tokens -> v6.7.1.0
System.IdentityModel.Tokens.Jwt -> v6.7.1.0

What are the DLLs versions you have?

1 Like

Make sure you are using correct API secret and Key, and your account supports API calls (i.e. not a free one, it may’ve changed lately though)
LogIn Here (https://marketplace.zoom.us/user/build)
Make sure your app is JWT and its active


Here is the class that generates my token

using System;
using System.Text;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;

namespace ZoomIntegration.Configuration {
    
    public class ZoomToken
    {
        public ZoomToken(string ZoomApiKey, string ZoomApiSecret )
        {   
            DateTime Expiry = DateTime.UtcNow.AddMinutes(5);
            string ApiKey = ZoomApiKey;
            string ApiSecret = ZoomApiSecret;

            int ts = (int)(Expiry - new DateTime(1970, 1, 1)).TotalSeconds;

            // Create Security key  using private key above:
            // note that latest version of JWT using Microsoft namespace instead of System
            var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(ApiSecret));

            // Also note that securityKey length should be >256b
            // so you have to make sure that your private key has a proper length
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            //Finally create a Token
            var header = new JwtHeader(credentials);

            //Zoom Required Payload
            var payload = new JwtPayload
            {
                { "iss", ApiKey},
                { "exp", ts },
            };

            var secToken = new JwtSecurityToken(header, payload);
            var handler = new JwtSecurityTokenHandler();

            // Token to String so you can use it in your client
            var tokenString = handler.WriteToken(secToken);
            //string Token = tokenString;
            this.Token = tokenString;
        }
        
        public string Token { get; set; }
    }
    
}
//Here is the method to get Zoom users
private void GetAccountUsers(string ZoomApiKey, string ZoomApiSecret) {
            try
            {
                
                ZoomToken zt = new ZoomToken(ZoomApiKey, ZoomApiSecret);
                string Token = zt.Token;
                
                //Create new Request
                string BaseUrl = "https://api.zoom.us/v2/users?status=active&page_size=300&page_number=1";
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(BaseUrl);
                myHttpWebRequest.Method = "GET";
                myHttpWebRequest.ContentType = "application/json;";
                myHttpWebRequest.Accept = "application/json;";
                myHttpWebRequest.Headers.Add("Authorization", String.Format("Bearer {0}", Token));

                //Get the associated response for the above request
                HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                using (StreamReader MyStreamReader = new StreamReader(myHttpWebResponse.GetResponseStream(), true))
                {
                    this.AccountUsers = JsonConvert.DeserializeObject<AccountUsers>(MyStreamReader.ReadToEnd());
                }
                
                myHttpWebResponse.Close();
                myHttpWebResponse.Dispose();
        
            }
            catch (WebException ex)
            {
                int errorCode = (int)((HttpWebResponse)ex.Response).StatusCode;
                if (errorCode != 0)
                {
                    ErrorCode = errorCode;
                    Stream MyStream = ex.Response.GetResponseStream();
                    StreamReader MyStreamReader = new StreamReader(MyStream, true);
                    this.ZoomException = JsonConvert.DeserializeObject<ZoomErrorResponse>(MyStreamReader.ReadToEnd());                  

                    //would be nice to check ZoomException for Null before throwing
                    throw new Exception(this.ZoomException.Message);
                }
            }
        }

//Here are 3 models for the response
[JsonObject]
    public class AccountUsers{
        
        [JsonProperty("page_count")]
        public Int32 PageCount { get; set; }

        [JsonProperty("page_number")]
        public Int32 PageNumber { get; set; }
        
        [JsonProperty("page_size")]
        public Int32 PageSize { get; set; }
        
        [JsonProperty("total_records")]
        public Int32 TotalRecords { get; set; }
        
        [JsonProperty("users")]
        public List<User> Users { get; set;}
        
        
    }
    
    [JsonObject]
    public class User{
        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("first_name")]
        public string FirstName { get; set; }

        [JsonProperty("last_name")]
        public string LastName { get; set; }
        
        [JsonProperty("email")]
        public string Email { get; set; }

        [JsonProperty("type")]
        public Int32 Type { get; set; }

        [JsonProperty("pmi")]
        public string Pmi { get; set; }

        [JsonProperty("timezone")]
        public string TimeZone { get; set; }

        [JsonProperty("verified")]
        public Int32 Verified { get; set; }
        
        [JsonProperty("dept")]
        public string Department { get; set; }
        
        [JsonProperty("created_at")]
        public DateTime CreatedAt { get; set; }
        
        [JsonProperty("last_login_time")]
        public DateTime LastLoginTime { get; set; }
        
        [JsonProperty("last_client_version")]
        public string LastClientVersion { get; set; }
        
    }
    
    [JsonObject]
    public class ZoomErrorResponse {
    
        [JsonProperty("code")]
        public String Code { get; set; }
        
        [JsonProperty("message")]
        public String Message { get; set; }
    }

5 Likes