Server-to-Server Authentication in Zoom Using .NET Core

Introduction

Zoom provides a Server-to-Server OAuth (S2S OAuth) authentication method for secure API interactions between your application and Zoom services. This authentication method is recommended for server-based applications that do not require user authorization. This article will cover,

  • Setting up a Server-to-Server OAuth app in Zoom Marketplace
  • Generating an access token
  • Implementing authentication in an ASP.NET Core Web API
  • Creating Zoom meetings using the API

Prerequisites

Before you start, make sure you have,

  • A Zoom Developer Account (Zoom Marketplace)
  • An ASP.NET Core Web API project (minimum .NET 6)
  • HttpClient for making API calls
  • Postman or any API testing tool

Create a Server-to-Server OAuth App in Zoom

We'll first create an OAuth app in Zoom, enter the required details, and obtain all the necessary credentials for the next steps.

  1. Go to Zoom App Marketplace: Zoom Marketplace
  2. Click Develop > Build App.
    Build App
  3. Choose Server-to-Server OAuth.
     Server-to-Server OAuth
  4. Enter the required details (App Name, Description, Company Name, etc.).
  5. Generate Client ID, Client Secret, and Account ID.
  6. Set Scopes: Add permissions for required API access (e.g., meeting:read, meeting:write, user:read).
    Set Scopes
  7. Save the app and keep the credentials secure.
    Credentials secure

Configure ASP.NET Core Web API

Now we will create a Web API project and implement the zoom authentication process there.

Create an ASP.NET Core Web API project

Create Project

Add Zoom Credentials to appsettings.json

{
  "ZoomSettings": {
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "AccountId": "your-account-id",
    "AuthUrl": "https://zoom.us/oauth/token",
    "ApiBaseUrl": "https://api.zoom.us/v2/"
  }
}

Implement Zoom Authentication Service

We need a service to obtain an OAuth access token from Zoom. Now we will create a Services folder and inside that folder add a class ZoomAuthService as given below.

   public class ZoomAuthService
   {
       private readonly IConfiguration _configuration;
       private string _accessToken;
       private DateTime _tokenExpiry;

       public ZoomAuthService(IConfiguration config)
       {
           _configuration = config;
       }

       public async Task<string> GetAccessTokenAsync()
       {
           string zoomTokenUrl = _configuration["ZoomSettings:OAuthEndpoint"];
           string clientId = _configuration["ZoomSettings:ClientId"];
           string clientSecret = _configuration["ZoomSettings:ClientSecret"];
           string encodedCredentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}"));

           using (HttpClient client = new HttpClient())
           {
               client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encodedCredentials);
               client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

               var requestData = new List<KeyValuePair<string, string>>
               {
                   new KeyValuePair<string, string>("grant_type", "account_credentials"),
                   new KeyValuePair<string, string>("account_id",  _configuration["ZoomSettings:AccountId"])
               };

               var requestContent = new FormUrlEncodedContent(requestData);
               var response = await client.PostAsync(zoomTokenUrl, requestContent);
               var responseString = await response.Content.ReadAsStringAsync();

               if (response.IsSuccessStatusCode)
               {
                   var tokenResponse = JsonConvert.DeserializeObject<ZoomTokenResponse>(responseString);
                   return tokenResponse.access_token;
               }
               return null;
           }
       }
   }
   public class ZoomTokenResponse
   {
       public string access_token { get; set; }
       public int expires_in { get; set; }
   }

Implement API for Zoom Meeting Management

We will create a meeting service that interacts with Zoom’s API as given in the below code.

    public class ZoomMeetingService
    {
        private readonly ZoomAuthService _zoomAuthService;
        private readonly IConfiguration _config;

        public ZoomMeetingService(ZoomAuthService zoomAuthService, IConfiguration config)
        {
            _zoomAuthService = zoomAuthService;
            _config = config;
        }

        public async Task<ZoomMeetingResponse> CreateMeetingAsync(string topic, int duration)
        {
            string accessToken = await _zoomAuthService.GetAccessTokenAsync();
            string zoomApiUrl = $"{_config["ZoomSettings:APIBaseUrl"]}users/me/meetings";
            var body = new
            {
                topic = topic,
                type = 2, // Scheduled Meeting
                duration = duration,
                timezone = "UTC",
                settings = new { host_video = true, participant_video = true }
            };
            using (HttpClient client = new HttpClient())
            {
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var jsonContent = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json");
                var response = await client.PostAsync(zoomApiUrl, jsonContent);
                var responseString = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    return JsonConvert.DeserializeObject<ZoomMeetingResponse>(responseString);
                }
            }
            return null;
        }
    }
    public class ZoomMeetingResponse
    {
        [JsonProperty("id")]
        public long MeetingId { get; set; }
        [JsonProperty("join_url")]
        public string? JoinUrl { get; set; }
        [JsonProperty("start_url")]
        public string? StartUrl { get; set; }
    }

Create API Controller

[Route("api/[controller]")]
[ApiController]
public class ZoomController : ControllerBase
{
    private readonly ZoomMeetingService _zoomMeetingService;

    public ZoomController(ZoomMeetingService zoomMeetingService)
    {
        _zoomMeetingService = zoomMeetingService;
    }

    [HttpPost("create-meeting")]
    public async Task<IActionResult> CreateMeeting([FromBody] CreateMeetingRequest request)
    {
        var result = await _zoomMeetingService.CreateMeetingAsync(request.Topic, request.Duration);
        return Ok(result);
    }
}
public class CreateMeetingRequest
{
    public string Topic { get; set; }
    public int Duration { get; set; }
}

Test API Using Swagger

Now we can test the endpoint as given in the below image.

Test API

Conclusion

In this article, we implemented Server-to-Server OAuth authentication in Zoom using an ASP.NET Core Web API. We covered.

  • Creating a Server-to-Server OAuth App in Zoom Marketplace
  • Generating and managing an OAuth token
  • Creating meetings using Zoom’s API

This setup can be extended to support webinars, users, recordings, and more.

Thank You, and Stay Tuned for More!

More Articles from my Account

Up Next
    Ebook Download
    View all
    Learn
    View all