JWT With Zoom

The Zoom API uses JSON Web Tokens (JWT) to authenticate account-level access. These tokens offer a method to establish secure server-to-server authentication by transferring a compact JSON object with a signed payload of your account’s API Key and Secret.

Note: JWT may only be used for internal applications and processes. All apps created for third-party usage must use our OAuth app type.

When authenticating to the Zoom API, a JWT should be generated uniquely by a server-side application and included as a Bearer Token in the header of each request. Follow this guide to set up the generation and structure of these tokens.

On This Page

JSON Web Tokens with SDK apps
Some SDK apps use JWT to authenticate account-level SDK Keys and Secrets to initialize the app. These tokens will follow the same structure as with API Keys and Secrets.

Accessing your API Key & Secret

JWT apps provide an API Key and Secret required to authenticate with JWT. To access the API Key and Secret, Create a JWT App on the Marketplace. After providing basic information about your app, locate your API Key and Secret in the App Credentials page.

An account has only one API Key and Secret pair. If a JWT app has already been created, either by yourself or another developer on your account, the API Key and Secret can be viewed.

Note: As account-level apps, JWT apps require Developer Role Permission to create, edit, or access.

Generating JWTs

A single JWT consists of three components: Header, Payload, and Signature with a . separating each. For example: aaaaa.bbbbb.ccccc

The Zoom API recommends and supports libraries provided on JWT.io. While other libraries can create JWT, these recommended libraries are the most robust.

The Header includes the specification of the signing algorithm and type of token. alg notes the algorithm being used. Zoom APIs and SDKs use HMAC SHA256 (HS256). typ refers to the token type: JWT.

"alg": "HS256",
"typ": "JWT"

Note: The Zoom API uses HS256 to sign the token. Use of other algorithms is not supported.


The payload of a token contains the claims or the pieces of information being passed about the user and any metadata required. While there are three types of claims, registered, public, and private, we highly recommend using registered claims for interoperability. A payload will require an issuer (iss) and expiration time (exp).

  • iss, the issuer of the token, is your API Key.
  • exp is the expiration timestamp of the token in seconds since Epoch (unix epoch time).
"iss": "API_KEY",
"exp": 1496091964000

Note: The expiration time (exp) can be defined in a numeric date and time format.*

It is highly recommended to set the exp timestamp for a short period, i.e. a matter of seconds. This way, if a token is intercepted or shared, the token will only be valid for a short period of time.

Note: Though protected against tampering, the information contained in the Header and Payload is readable by anyone. Do not store confidential information in either of these elements.


The Signature of the token base64 encodes the header and payload, then includes the API Secret within the HMACSHA256 algorithm to securely sign the entire package.

base64UrlEncode(header) + "." +

Testing with JWTs

Within the App Credentials page of your JWT app, you will see an option to View JWT Token. Here you can quickly generate a temporary token using the current API Key and Secret for the given expiration time. This single temporary token can then be used to test Zoom APIs, but should never be used in production applications.

View JWT Token

Sample apps

Reference the following sample apps for a guide to generating and making requests using JWT:

Node JS: Sample Node app using jsonwebtoken

Sample code

The following code snippets can be used to get started making server-side API calls using JWT:

// Make Zoom API call
var options = {
uri: 'https://api.zoom.us/v2/users',
qs: {
status: 'active' // -> uri + '?status=active'
auth: {
//Provide your token here
'bearer': token
headers: {
'User-Agent': 'Zoom-Jwt-Request',
'content-type': 'application/json'
json: true // Automatically parses the JSON string in the response
.then(function (response) {
//logic for your response
console.log('User has', response);
.catch(function (err) {
// API call failed...
console.log('API call failed, reason ', err);
curl --request GET
--url 'https://api.zoom.us/v2/users?status=active&page_size=30&page_number=1'
--header 'authorization: Bearer { your_token }'
--header 'content-type: application/json'
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zoom.us/v2/users?status=active&page_size=30&page_number=1",
"authorization: Bearer 39ug3j309t8unvmlmslmlkfw853u8",
"content-type: application/json"
$response = curl_exec($curl);
$err = curl_error($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
import http.client
conn = http.client.HTTPSConnection("api.zoom.us")
headers = {
'authorization': "Bearer 39ug3j309t8unvmlmslmlkfw853u8",
'content-type': "application/json"
conn.request("GET", "/v2/users?status=active&page_size=30&page_number=1", headers=headers)
res = conn.getresponse()
data = res.read()
require 'uri'
require 'net/http'
url = URI("https://api.zoom.us/v2/users?status=active&page_size=30&page_number=1")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(url)
request["authorization"] = 'Bearer 39ug3j309t8unvmlmslmlkfw853u8'
request["content-type"] = 'application/json'
response = http.request(request)
puts response.read_body
var client = new RestClient("https://api.zoom.us/v2/users?status=active&page_size=30&page_number=1");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer 39ug3j309t8unvmlmslmlkfw853u8");
IRestResponse response = client.Execute(request);

Need help?

If you're looking for help, try Developer Support or our Developer Forum. Priority support is also available with Premier Developer Support plans.