pyzoom icon indicating copy to clipboard operation
pyzoom copied to clipboard

Server-to-server Oauth ?

Open mboisson opened this issue 1 year ago • 7 comments

Hi, The Zoom API supports what they call "Server-to-server Oauth", which does not seem to require a call back URL. Can this be supported ?

mboisson avatar Nov 01 '23 15:11 mboisson

Example of how to use it https://www.makeuseof.com/generate-server-to-server-oauth-zoom-meeting-link-python/

mboisson avatar Nov 01 '23 17:11 mboisson

Hi, this is already built in. To generate credentials locally just run in your terminal:

python -c "from pyzoom import oauth_wizard; oauth_wizard()"

And follow the instructions.

licht1stein avatar Nov 01 '23 18:11 licht1stein

Ok, I read more carefully. We don't have support for s2s-oauth, only normal oauth. If you want you can make a PR to add it.

licht1stein avatar Nov 01 '23 18:11 licht1stein

Example of how to use it https://www.makeuseof.com/generate-server-to-server-oauth-zoom-meeting-link-python/

Thanks, I've used it here, which other people might also like to use as a base :slightly_smiling_face: https://github.com/owen9825/zoom_attendance

owen9825 avatar Nov 11 '23 03:11 owen9825

@owen9825

So basically we need something similar to this as one of the ways to initialise the ZoomClient?

def get_access_token(account_id: str) -> Optional[str]:
    # https://developers.zoom.us/docs/internal-apps/s2s-oauth/
    client_id = os.getenv("ZOOM_CLIENT_ID")
    client_secret = os.getenv("ZOOM_CLIENT_SECRET")
    # https://www.makeuseof.com/generate-server-to-server-oauth-zoom-meeting-link-python/
    data = {
        "grant_type": "account_credentials",
        "account_id": account_id,
        "client_secret": client_secret,
    }
    headers = {"Host": "zoom.us"}
    response = requests.post(
        auth_token_url, auth=(client_id, client_secret), data=data, headers=headers
    )
    if not response.ok:
        logger.warning(
            "There was an error (%s) authenticating at %s: %s",
            response.status_code,
            response.url,
            response.text,
        )
        return None
    body = response.json()
    return body.get("access_token")

licht1stein avatar Mar 11 '24 21:03 licht1stein

I forgot I had opened this, but we ended-up developing our own class for interfacing with Zoom. Here is the portion of the class code for getting the authorization headers:

    auth_token_url = "https://zoom.us/oauth/token"
    api_base_url = "https://api.zoom.us/v2"


    def __init__(self, account_id, client_id, client_secret, timezone = "America/Montreal", user = "me"):
        '''Initialize the Zoom interface object with API credentials

        Reference: https://developers.zoom.us/docs/zoom-rooms/s2s-oauth/

        Arguments:
            account_id -- string. Usually stored secretly
            client_id -- string. Usually stored secretly
            client_secret -- string. Usually stored secretly
            timezone -- string. Valid values are in all_timezones from pytz
                https://pythonhosted.org/pytz/#helpers
            user -- string. Zoom username, either email address or "me"
        '''

        self.account_id = account_id
        self.client_id = client_id
        self.client_secret = client_secret
        self.timezone = timezone
        self.user = user


    def get_authorization_header(self):
        '''Get the OAuth temporary authorization token

        Reference:
            https://developers.zoom.us/docs/zoom-rooms/s2s-oauth/
            https://www.makeuseof.com/generate-server-to-server-oauth-zoom-meeting-link-python/

        Returns: dictionary with keys "Authorization" and "Content-Type"
        '''

        response = requests.post(
            self.auth_token_url,
            auth=(self.client_id, self.client_secret),
            data={
                "grant_type": "account_credentials",
                "account_id": self.account_id,
                "client_secret": self.client_secret
            })

        response_data = response.json()

        assert response.status_code == 200, response_data['message']

        access_token = response_data["access_token"]
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json"
        }

        return headers

Then it can be used, for example:

    def create_meeting(self, topic, duration, start_date, start_time):
        headers = self.get_authorization_header()

        # https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingCreate
        payload = {
            "topic": topic,
            #"schedule_for": "user@a",
            #"alternative_hosts": "a,b,c,d",
            "duration": duration,
            #"host_video": true,
            #"jbh_time": 5,
            #"join_before_host": "true",
            'start_time': f'{start_date}T{start_time}',
            "timezone": self.timezone,
            "type": 2,
        }

        resp = requests.post(f"{self.api_base_url}/users/{self.user}/meetings",
                             headers=headers,
                             json=payload)

        if resp.status_code!=201:
            print("Unable to generate meeting link")
        response_data = resp.json()

        content = {
                    "meeting_url": response_data["join_url"],
                    "password": response_data["password"],
                    "meetingTime": response_data["start_time"],
                    "purpose": response_data["topic"],
                    "duration": response_data["duration"],
                    "message": "Success",
                    "status":1
        }
        return content

mboisson avatar Mar 11 '24 22:03 mboisson

@owen9825

So basically we need something similar to this as one of the ways to initialise the ZoomClient?

def get_access_token(account_id: str) -> Optional[str]:
    # https://developers.zoom.us/docs/internal-apps/s2s-oauth/
    client_id = os.getenv("ZOOM_CLIENT_ID")
    client_secret = os.getenv("ZOOM_CLIENT_SECRET")
    # https://www.makeuseof.com/generate-server-to-server-oauth-zoom-meeting-link-python/
    data = {
        "grant_type": "account_credentials",
        "account_id": account_id,
        "client_secret": client_secret,
    }
    headers = {"Host": "zoom.us"}
    response = requests.post(
        auth_token_url, auth=(client_id, client_secret), data=data, headers=headers
    )
    if not response.ok:
        logger.warning(
            "There was an error (%s) authenticating at %s: %s",
            response.status_code,
            response.url,
            response.text,
        )
        return None
    body = response.json()
    return body.get("access_token")

sorry, I've finished work on this. I don't wish to return to it and go through the implementation a 2nd time. All the best

owen9825 avatar Mar 11 '24 22:03 owen9825