Server-to-Server OAuth response


I’m converting a JWT application to the Server-to-Server OAuth method.
The response of the initial request returns 4 values:

  • access_token
  • token_type
  • expires_in
  • scope

Does the header format changes ?
Do we need to use the scope in any manner ?

With the access_token received using I request an end point adding the following headers
{'Authorization': 'Bearer {access_token}', 'Content-type': 'application/json'}

but the result is 400 error : {'code': 200, 'message': 'Invalid api key or secret.'}

What’s wrong ?


@EVant ,

Thank you for posting in the zoom developer forum --I’m happy to help here! As a start, can you share a screenshot of the code snippet used to handle the server-to-server request?

In the meantime, to help developers get started fast, we create some Server-to-Server OAuth samples. I’ve linked the sample apps below for your reference.

Let me know if you have questions.

Where do I find the account_id? My marketplace url is App Marketplace /credentials, so I tried to use Sh…XA, but that didn’t work.

When I post

POST /oauth/token?grant_type=account_credentials&account_id=[REDACTED] HTTP/1.1
User-Agent: GuzzleHttp/7
Content-Type: application/json
Authorization: Basic RxxxxxxZQ
Content-Length: 2

I get a response of unsupported grant type

This is the Python code to get the token and generate the headers

		with httpx.Client(auth=(ClientId,ClientSecret)) as client:
			params = {'grant_type': 'client_credentials'}
			r ='', params=params)

		token = r.json()["access_token"]
		headers = {'Authorization': f'Bearer {token}',
					'Content-type': 'application/json'}

The response seems ok
{"access_token":"eyJhbGciOiJIUzUx....J7hfYQ","token_type":"bearer","expires_in":3600,"scope":"meeting:master meeting:read:admin meeting:read:admin:sip_dialing meeting:write:admin meeting_token:read:admin:live_streaming meeting_token:read:admin:local_archiving meeting_token:read:admin:local_recording recording:master recording:read:admin recording:write:admin room:master room:read:admin room:write:admin user:master user:read:admin user:write:admin webinar:master webinar:read:admin webinar:write:admin webinar_token:read:admin:live_streaming webinar_token:read:admin:local_archiving webinar_token:read:admin:local_recording"}

With this header I then call an a end point

with httpx.Client(http2=True, headers=headers,  verify=True) as client:
           url = f'{id}/meetings?\
           r = client.get(url)


Thanks for sharing. It looks like you were able to get up and running. For reference, here is another simple Python script you can use to get the Access token with your server -to-server App credentials:

import requests


payload = ""
headers = {
  'Authorization': 'Basic {token}'

response = requests.request("POST", url, headers=headers, data=payload)


@scott ,

Welcome to the Zoom Developer Forum. For context, are you looking for your account id to use with server to -server OAuth? Or are you asking for general knowledge? If the latter, the Get a user API response will include the account id. If the former, when you create a Server-to-server app, you can find your account on the App credentials screen of your Marketplace App. Here is a screenshot of what that looks like :

Server-to-server app credentials screenshot:

Get a user API

Sorry, I don’t understand everything.

In your example your are using account_credentials
What is the difference with client_credentials ?

Do I need to use the first request with Client_Id and Client_Secret to get a token and then use it with your script above ?

I tried your request (alone) with postman and it generates an error
{"reason":"Invalid Client Id and Client Secret","error":"invalid_client"}

Great question, @EVant ! You can use client_credentials or account_credentials with the Server-to-server. See our Server-to-Server OAuth support documentation for a detailed description of the difference between account_credentials and client_credentials

Create a Server-to-Server OAuth app

The code snippet was actually provided via a successful Server-to-server Postman request.

Here is a screenshot of how the request was setup in Postman for context :

Postman Params Tab

Postman Authorization Tab

Thanks!! The reason I was having such a hard time is that I had made an OAuth app instead of a Server-to-server OAuth app. I didn’t realize they were different. Couldn’t figure out why it was giving me a refresh token…


Thank you for providing your feedback there. We’ll see if we can improve our documentation around this to make it more clear.