"code":124,"message":"Invalid access token."

Hi team,

I’m facing the error “Invalid access token” (code error 124) while trying to create a new meeting via the API.
I remove app and restart again but the same code error
The scopes I have are : meeting:write meeting:read user_zak:read
Please tell me why I am getting this error and how to remove it?

@touch.ag how are you generating your access token?

Hi Chun Siong for your reply:
i generate my access token like this :

$private function getAccessToken($code){
$CLIENT_ID = “xxxxxxxxx”;
$CLIENT_SECRET = “xxxxxxxxxxxxxxxx”;
$REDIRECT_URI = ‘xxxxxxxxxxxxxxxxxxxxxxxx’;

$token_url = 'https://zoom.us/oauth/token';

$token_data = array(
    'grant_type' => 'authorization_code',
    'code' => $code,
    'redirect_uri' => $REDIRECT_URI

$token_headers = array(
    'Authorization: Basic ' . base64_encode("$CLIENT_ID:$CLIENT_SECRET")

$ch = curl_init($token_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($token_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $token_headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$token_response = curl_exec($ch);
$token_data = json_decode($token_response, true);

if ($token_data && isset($token_data['access_token'])) {
    return $token_data['access_token'];
} else {
    return false;



@touch.ag I’ll PM you for this

We’re just migrating to the new Zoom library, which requires using the JWT instead of app-id and app-secret.
I’m getting the same error message: errorCode = 4, internalErrorCode=124.

This is the code how the JWT is generated using Scala with BouncyCastle.

  override def createJwt(issuedAt: Instant, role: Int, meetingNumber: Long): String = {

    val expiresAt = issuedAt.plus(3, HOURS)
    val header = """{"typ":"JWT","alg":"HS256"}"""
    val payload = s"""{"appKey":"$clientId","sdkKey":"$clientId","mn":$meetingNumber,"role":$role,"iat":${issuedAt.getEpochSecond},"exp":${expiresAt.getEpochSecond},"tokenExp":${expiresAt.getEpochSecond}}"""

    val encodedHeaderAndPayload = java.util.Base64.getUrlEncoder.withoutPadding().encodeToString(header.getBytes) + "." + java.util.Base64.getUrlEncoder.withoutPadding().encodeToString(payload.getBytes)

    val hmac = new HMac(new SHA256Digest())
    hmac.init(new KeyParameter(clientSecret.getBytes("UTF-8")))
    val result = new Array[Byte](hmac.getMacSize)
    val bytes = encodedHeaderAndPayload.getBytes("UTF-8")
    hmac.update(bytes, 0, bytes.length)
    hmac.doFinal(result, 0);

    return encodedHeaderAndPayload + "." + java.util.Base64.getUrlEncoder.withoutPadding().encodeToString(result)

Checking the JWT on jwt.io with the client-secret yields in a valid signature. Here is an example JWT signed with the client-secret the-very-long-and-secure-client-secret:

  "typ": "JWT",
  "alg": "HS256"
  "appKey": "the-client-id",
  "sdkKey": "the-client-id",
  "mn": 123456,
  "role": 0,
  "iat": 1705665600,
  "exp": 1705676400,
  "tokenExp": 1705676400


Are the datatypes for role and mn correct? They are not stated explicitly in the documentation, so I inferred them as numbers, not strings.

Any help is appreciated. @chunsiong.zoom

@martin.ley I’ll PM you for this