C# sample

Zoom API and SDK reference

Published ASP.NET Core examples for Zoom webhooks, Server-to-Server OAuth, OAuth redirects, Meeting SDK signatures, token refresh, and REST API calls.

GitHub source

Live demo

WebhookInspect the webhook endpoint. S2S OAuthRequest an account access token. OAuth redirectExchange an authorization code. Refresh tokenExchange a refresh token for a new access token. REST APICreate a sample meeting with an access token. Meeting SDKGenerate a Meeting SDK signature. Install URLStart the Zoom OAuth authorization flow.

Code samples

Webhook handler



using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public static class webhook
{
    public static Task GetWebhook(HttpContext context)
    {
        return Task.Run(() =>
        {
            // Handle GET request logic here
            context.Response.WriteAsync("GET request received.");
        });
    }

    public static Task PostWebhook(HttpContext context)
    {
        return Task.Run(async () =>
        {
            // Get the request content as a string asynchronously
            string requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();

            try
            {
                JObject jsonObject = JObject.Parse(requestBody);
                if (jsonObject["event"]?.ToString() != "endpoint.url_validation")
                {
                    await context.Response.WriteAsync("Success.");
                    return;
                }

                JObject payload = (JObject)jsonObject["payload"];
                string plainToken = payload["plainToken"].ToString();
                string secretToken = Environment.GetEnvironmentVariable("OAUTH_SECRET_TOKEN") ?? "";
                string encryptedToken = GetHash(plainToken, secretToken);

                var response = new
                {
                    plainToken,
                    encryptedToken
                };
                context.Response.ContentType = "application/json";

                // Write the JSON response
                await context.Response.WriteAsync(JsonConvert.SerializeObject(response));

            }
            catch (Exception ex)
            {
                await context.Response.WriteAsync("Error: " + ex.ToString());
            }

        });
    }

    static string GetHash(string text, string key)
    {
        using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
        {
            byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(text));
            return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
        }
    }
}



Server-to-Server OAuth token


using Newtonsoft.Json;
using System.Text;
using System.Text.Json;



    public class s2soauth
    {

        public static Task S2SOauth(HttpContext context)
        {
            return Task.Run(async () =>
            {

                string s2s_oauth_client_id = Environment.GetEnvironmentVariable("S2S_OAUTH_CLIENT_ID"); 
                string s2s_oauth_client_secret = Environment.GetEnvironmentVariable("S2S_OAUTH_CLIENT_SECRET"); 
                string s2s_oauth_account_id = Environment.GetEnvironmentVariable("S2S_OAUTH_ACCOUNT_ID");


                // Access the environment variables
                var clientId = s2s_oauth_client_id;
                var clientSecret = s2s_oauth_client_secret;
                var accountId = s2s_oauth_account_id;
                var oauthUrl = $"https://zoom.us/oauth/token?grant_type=account_credentials&account_id={accountId}";

                try
                {
                    // Create the Basic Authentication header
                    var authHeader = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));

                    // Initialize HttpClient
                    using var client = new HttpClient();

                    // Create request message
                    var request = new HttpRequestMessage(HttpMethod.Post, oauthUrl);
                    request.Headers.Add("Authorization", $"Basic {authHeader}");

                    // Send request and get response
                    var response = await client.SendAsync(request);

                    // Check if the request was successful (status code 200)
                    if (response.IsSuccessStatusCode)
                    {
                        // Parse the JSON response to get the access token
                        var jsonResponse = await response.Content.ReadAsStringAsync();
                        var accessToken = JsonDocument.Parse(jsonResponse).RootElement.GetProperty("access_token").GetString();

                        // Set the "Content-Type" header to "application/json"
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(accessToken));
                      
                    }
                    else
                    {
                        await context.Response.WriteAsync($"OAuth Request Failed with Status Code: {response.StatusCode}");
                      
                    }
                }
                catch (Exception e)
                {
                    await context.Response.WriteAsync($"An error occurred: {e.Message}");
                   
                }


            });
        }

   
    }



    
    

OAuth redirect exchange



using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.IO;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public static class redirectforoauth
{
 
    public static Task RedirectForOauth(HttpContext context)
    {
        return Task.Run(async () =>
        {

          
            String AppClientID = Environment.GetEnvironmentVariable("OAUTH_CLIENT_ID"); ;
            String AppClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET"); ;
            String redirectURL = "https://csharp.asdc.cc/redirectforoauth";

            var authorizationToken = context.Request.Query["code"].ToString();

            try
            {
                using (HttpClient _httpClient = new HttpClient())
                {
                    var url = "https://zoom.us/oauth/token";

                    using var client = new HttpClient();

                    // Encode the client ID and client secret
                    var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{AppClientID}:{AppClientSecret}"));
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);


                    var content = new FormUrlEncodedContent(new Dictionary
                {
                    { "grant_type", "authorization_code" },
                    { "redirect_uri", redirectURL },
                    { "code", authorizationToken }
                });

                    var response = await client.PostAsync(url, content);


                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync();
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(responseContent));

                    }
                    else
                    {
                        // Handle error response
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(response.StatusCode));

                    }
                }
            }
            catch (HttpRequestException ex)
            {
                // Handle HTTP request exceptions
                Console.WriteLine($"HTTP Request Exception: {ex.Message}");
                //throw new Exception($"HTTP Request Exception: {ex.Message}");
            }
            catch (System.Text.Json.JsonException ex)
            {
                // Handle JSON parsing exceptions
                Console.WriteLine($"JSON Parsing Exception: {ex.Message}");
                throw new Exception($"JSON Parsing Exception: {ex.Message}");
            }
            catch (Exception ex)
            {
                // Handle other exceptions
                Console.WriteLine($"Exception occurred: {ex.Message}");
                throw new Exception($"Exception occurred: {ex.Message}");
            }
        });
    }

    internal static RequestDelegate RedirectForOauth(string? oAUTH_CLIENT_ID, string? oAUTH_CLIENT_SECRET)
    {
        throw new NotImplementedException();
    }
}





Meeting SDK signature


            
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public static class meetingsdk
{

    public static Task MeetingSDK(HttpContext context)
    {
        return Task.Run(async () =>
        {

            string MSDK_CLIENT_ID = Environment.GetEnvironmentVariable("MSDK_CLIENT_ID");
            string MSDK_CLIENT_SECRET = Environment.GetEnvironmentVariable("MSDK_CLIENT_SECRET");


            var authorizationToken = context.Request.Query["code"].ToString();
            
            var currentDateOffset = DateTimeOffset.UtcNow;
            var epochTime = (int)currentDateOffset.ToUnixTimeSeconds();

            var epochTime48HoursLater = epochTime + 172800; // 172800 seconds = 2 days
            DateTime epochDateTimeExpiry = DateTimeOffset.FromUnixTimeSeconds(epochTime48HoursLater).UtcDateTime;

            var sdkSecret = MSDK_CLIENT_SECRET;
            var appKey = MSDK_CLIENT_ID;
            var data = new Dictionary
        {
            { "appKey", appKey },
            { "iat", epochTime },
            { "exp", epochTime48HoursLater },
            { "tokenExp", epochTime48HoursLater },
            { "mn", 9898533313 },
            { "role", 1 }
        };
            var meetingSdkKey = GenerateSignature(data, sdkSecret, epochDateTimeExpiry);


            await context.Response.WriteAsync(JsonConvert.SerializeObject(meetingSdkKey));
        });

        static string GenerateSignature(Dictionary data, string secret, DateTime epochDateTimeExpiry)
        {
            var claims = data.Select(kv => new Claim(kv.Key, kv.Value.ToString()));
            var identity = new ClaimsIdentity(claims, "Custom");
            //var handler = new JwtSecurityTokenHandler();
            //var securityToken = handler.CreateToken(new SecurityTokenDescriptor
            //{
            //    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), SecurityAlgorithms.HmacSha256),
            //    Subject = identity,
            //    Expires = epochDateTimeExpiry, 
            //    NotBefore= null
            //});
            //return handler.WriteToken(securityToken);
            // Create JWT token without setting the "nbf" claim
            var securityToken = new JwtSecurityToken(
                claims: identity.Claims,
                expires: epochDateTimeExpiry,
                signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), SecurityAlgorithms.HmacSha256),
                notBefore: null  // Exclude the "nbf" claim
            );

            var handler = new JwtSecurityTokenHandler();
            return handler.WriteToken(securityToken);
        }

    }
}

        
        

OAuth refresh token


            
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public static class oauthrefreshtoken
{

    public static Task OauthRefreshToken(HttpContext context)
    {
        return Task.Run(async () =>
        {


            var oauthClientId = Environment.GetEnvironmentVariable("OAUTH_CLIENT_ID");
            var oauthClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET");
            var refreshToken = context.Request.Query["code"].ToString();

            var url = "https://zoom.us/oauth/token";

            var credentials = $"{oauthClientId}:{oauthClientSecret}";
            var credentialsEncoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));

            var data = new Dictionary
            {
                { "grant_type", "refresh_token" },
                { "refresh_token", refreshToken }
            };

            var content = new FormUrlEncodedContent(data);

            using var client = new HttpClient();
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentialsEncoded);

        

            var response = await client.PostAsync(url, content);

            if (response.IsSuccessStatusCode)
            {
                var jsonResponse = await response.Content.ReadAsStringAsync();

                var accessToken = JsonDocument.Parse(jsonResponse).RootElement.GetProperty("access_token").GetString();

                // Set the "Content-Type" header to "application/json"
                await context.Response.WriteAsync(JsonConvert.SerializeObject(accessToken));
            }
            else
            {
                await context.Response.WriteAsync($" Request Failed with Status Code: {response.StatusCode}");

            }
        });
    }

}



REST API call


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class callapi
{
    public static Task CallAPI(HttpContext context)
    {
        return Task.Run(async () =>
        {
            // Fetch access_token from query string
            var access_token = context.Request.Query["access_token"];
            if (string.IsNullOrWhiteSpace(access_token))
            {
                context.Response.StatusCode = 400;
                await context.Response.WriteAsync("Add ?access_token=your_token to call the API");
                return;
            }

            // Meeting data
            var meeting_data = new
            {
                topic = "hello world",
                type = 2,
                start_time = DateTime.UtcNow.AddHours(1).ToString("yyyy-MM-ddTHH:mm:ssZ"),
                duration = 120,
                password = "12345678",
                agenda = "40 mins limit demonstration",
                pre_schedule = false,
                timezone = "Asia/Singapore",
                default_password = false
            };

            // Zoom API endpoint
            var api_url = "https://api.zoom.us/v2/users/me/meetings";

            // Send POST request to create meeting
            using var client = new HttpClient();
            using var request = new HttpRequestMessage(HttpMethod.Post, api_url);
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
            request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            request.Content = new StringContent(JsonSerializer.Serialize(meeting_data), Encoding.UTF8, "application/json");

            var response = await client.SendAsync(request);

            // Return response
            await context.Response.WriteAsync("Meeting Details: " + await response.Content.ReadAsStringAsync());
        });


    }
}


 

Environment variables

        
                S2S_OAUTH_CLIENT_ID='xxxxxxxxxx'
                S2S_OAUTH_CLIENT_SECRET='xxxxxxxxxx'
                S2S_OAUTH_ACCOUNT_ID='xxxxxxxxxx'
                OAUTH_SECRET_TOKEN='xxxxxxxxxx'
                OAUTH_CLIENT_ID='xxxxxxxxxx'
                OAUTH_CLIENT_SECRET='xxxxxxxxxx'
                MSDK_CLIENT_SECRET='xxxxxxxxxx'
                MSDK_CLIENT_ID='xxxxxxxxxx'