Zoom OAuth with a NuxtJS App, Part 1

Zoom OAuth with a NuxtJS App, Part 1

Setup and Preliminary ServerMiddleware Work

ยท

7 min read

Some weeks ago we discussed how to do Zoom OAuth with Next.js. As was said there, we need to authenticate our calls to Zoom's API in order for us to use it, and we can either do this with JWT or OAuth. If you're building a third-party service or application, OAuth is the way to go. We'll not be using an SDK for this tutorial; everything will be done from scratch.

Preliminaries:

  • Make sure you have a Zoom account and register your app in Zoom's Marketplace. More details on how to do so can be found here.
  • Download and install Ngrok. We'll need it because Zoom doesn't allow redirects to localhost.
    • Run Ngrok by using your terminal and running ngrok http 3000 wherever your Ngrok executable file is stored.
  • Presuming that you already have Nuxt downloaded and set up, you'll need to set up your environment variables.
    • Create a .env file. Here we will house our Zoom Client ID and Client Secret. You should place your Ngrok URL here too.
    • For this tutorial, we'll name our variables thusly: NUXT_ENV_ZOOM_CLIENT_ID, NUXT_ENV_ZOOM_CLIENT_SECRET, and NUXT_ENV_BASE_URL. NB: We use the prefix NUXT_ENV_to inject it straight into the process environment, so we don't have to do anything extra in nuxt.config.js.
  • Insert the Ngrok URL into 'Redirect URL for OAuth' and 'Whitelist URL' fields on the App Credentials page of your Zoom app.
  • Scopes are extremely important so don't forget to add them to your app dashboard!
  • Run npm run dev!

The Work Begins: Here we're going to make a simple link that when clicked will help kick off the whole process.

  • In your pages folder, create index.vue if it's not already there. We will put link as a property so we can manipulate it and bind it to our a tag via v-bind:href. We need the link to be available when our page is mounted, so we'll use Vue's mounted hook.
  • We'll also be using the URL interface which should be available to all modern browsers.
<template>
    <a :href="link">Create Zoom link</a>
</template>

<script>
export default {
    data(){
        return {
            link: '',
        }
    }, 
    mounted(){
        this.getZoomLink()
    },
    methods: {
        getZoomLink(){
            let url = new URL('https://zoom.us/oauth/authorize')
            url.searchParams.set('response_type', 'code')
            url.searchParams.set('redirect_uri', process.env.url)
            url.searchParams.set('client_id', process.env.zoomclient)
            this.link = url.href
        }, 
    }    
}
</script>
  • When you click the link, a page describing your app and the info that it's requesting will show up (if you're logged in). Once you click on the 'Authorize' button, it will redirect you to the redirect_uri that you set.

The Work Continues: You should now see code in the query string in your browser's URL bar. We'll need to use this string to get our access code.

  • To get our code, we'll use this.$route.query. It returns an object, so we'll first check to see if it is empty with Object.keys() to ensure we only run it when this query string is set. We'll pass it on to a property called code so that we can use its value elsewhere.
    • We'll be using the created lifecycle hook instead of mounted for this part. This hook is usually used for fetching data on initialization and fires right before the mounting of our component.
data(){
    return {
        link: '',
        code: ''
    }
},
created(){
    const obj_length = Object.keys(this.$route.query).length
    if (obj_length > 0){
        this.code = this.$route.query.code
    }
},
mounted(){
    this.getZoomLink()
},
  • Now we'll create a method that will send this data to our serverMiddleware. It will run immediately after we get the code string.
    created(){
      const obj_length = Object.keys(this.$route.query).length
      if (obj_length > 0){
          this.code = this.$route.query.code
          this.getZoomUser()
      }
    },
    ...
    methods: {
      async getZoomUser(){
          let options = {
              method: 'GET',
              headers: {
                  'Content-Type': 'application/json'
              }
          }  
          let response = await fetch(`/api/access-token?code=${this.code}`, options)
          let user = await response.json()
      },
    }
    

The Work Ends: All Zoom API endpoints will need to be accessed from the server-side, hence, we'll need to use Nuxt serverMiddleware. Seriously, don't even try using the client. You'll get a lot of CORS issues. Our serverMiddleware will act as an API that will communicate with Zoom's API.

  • The first thing we'll need to do is create an api/ folder in the root, then create a file that will house our serverMiddleware. I've named it zoom-token.js.
  • Now we'll register our serverMiddleware in our nuxt.config.js file. We'll set a proxy for our API, and tell Nuxt where exactly the API's handler function is.
serverMiddleware: [
    {path: '/api/access-token', handler: '~/api/zoom-token.js'},
]
  • Now we can begin work on our serverMiddleware. If we log our request to the console (in our terminal, not the browser), we'll see all the related properties, methods, and data, including our query string.
export default function(req, res){
    console.log(req)
}

Conclusion:

  • In our next post, we'll go deeper into serverMiddleware and show how we can return our data to the client-side.
ย