Invalid Access Token When Creating a new Meeting

Description
After the user authenticates my app, I then get a invalid authorization code error returned from the api endpoint.

Error
reason: ‘Invalid authorization code 2eVuv4dL4b_ZMs9PfYuSe6LhmQF6Fw45w’,

Which App Type (OAuth / Chatbot / JWT / Webhook)?
OAuth - Account level

Which Endpoint/s?
https://zoom.us/oauth/token?grant_type=authorization_code

Additional context

Here is my code currently:
app.get('/create', (req, res) => {

    // Step 1: 
    // Check if the code parameter is in the url 
    // if an authorization code is available, the user has most likely been redirected from Zoom OAuth
    // if not, the user needs to be redirected to Zoom OAuth to authorize

    if (req.query.code) {

        // Step 3: 
        // Request an access token using the auth code
        console.log('Code returned', req.query.code);
        let url = 'https://zoom.us/oauth/token?grant_type=authorization_code&code=' + req.query.code + '&redirect_uri='+process.env.redirectURL+'/create';

        rp.post(url, (error, response, body) => {

            // Parse response to JSON
            body = JSON.parse(body);
            console.log(body);
            // Logs your access and refresh tokens in the browser
            console.log(`access_token: ${body.access_token}`);
            console.log(`refresh_token: ${body.refresh_token}`);

            if (body.access_token) {

                // Step 4:
                // We can now use the access token to authenticate API calls

                // Send a request to get your user information using the /me context
                // The `/me` context restricts an API call to the user the token belongs to
                // This helps make calls to user-specific endpoints instead of storing the userID
                const options = {
        
                    uri: "https://api.zoom.us/v2/users/me/meetings", 
                    auth: {
                        'bearer': body.access_token
                    },
                    method: 'POST',
                    headers: {
                        'User-Agent': 'Zoom-api-Jwt-Request',
                        'content-type': 'application/json'
                    },
                    json: true, //Parse the JSON string in the response
                    body:{
                        "topic": "Test Meeting",
                        "type": 1,
                        "agenda": "Talking about firebase.",
                        "join_before_host": true,
                        "settings": {
                            "host_video": false,
                            "participant_video": true,
                            "mute_upon_entry": true,
                            "watermark": false,
                            "audio": "voip",
                            "auto_recording": "cloud",
                            "use_pmi":true
                        }
                    }
                }
                rp(options, (error, response, body) => {
                    if (error) {
                        console.log('API Response Error: ', error)
                    } else {
                        body = JSON.parse(body);
                        // Display response in console
                        console.log('API call ', body);
                        // Display response in browser
                        var JSONResponse = '<pre><code>' + JSON.stringify(body, null, 2) + '</code></pre>'
                        res.send(JSONResponse);
                    }
                }).auth(null, null, true, body.access_token);

            } else {
                // Handle errors, something's gone wrong!
            }

        }).auth(process.env.clientID, process.env.clientSecret);

        return;

    }

    // Step 2: 
    // If no authorization code is available, redirect to Zoom OAuth to authorize
    res.redirect('https://zoom.us/oauth/authorize?response_type=code&client_id=' +process.env.clientID + '&redirect_uri=https://jive-zoom.web.app/create')
});

Hey @twalkerjr22_1,

Thanks for reaching out about this and happy to help.

The error you’re receiving typically means that the code you’re grabbing from the redirect URL is outdated or invalid. Based on your code snippet, it seems like perhaps you’re having users reauthorize your app based on a check for a previous code—is this right? If so, I should note that this should just be a 1 time operation: when a user authorizes your app, you will grab that code to request an acces_token initially, from which point on you will refresh your access_tokens. You shouldn’t need to keep authorizing the app, however.

Can you make sure you’re only authorizing once and using the code appended to the redirect_url as soon as you receive it?

Thanks,
Will

Ah this makes sense. So after the initial authentication from the user and the access token is returned as well as the refresh_token, how do I use these in the future to make calls on that users behalf?

Do both of these need to be stored in some type of database for each user or could there be one refresh or access token used across the entire app?

Just trying to understand how it works.

Thanks for the help so far!

Hey @twalkerjr22_1,

That’s right—you will want to store both the access_token and refresh_token that you receive in response from our OAuth endpoint. You will then use the refresh_token to update to request a new access_token when the current one expires—this will then return a new pair of both tokens to continue this process.

You can also read about this here:

Let me know if this helps to clarify!

Best,
Will

Gotcha. So you must store an access token and refresh token for each user in a database?

That’s correct @twalkerjr22_1 :slight_smile:

Is it possible to store these in http only cookies?

Hi @twalkerjr22_1,

We don’t recommend taking this approach. Best practice would be to store these tokens server side.

Thanks,
Will