Google provides an API to connect your SaaS, such as Workarise, with their services, such as Google Calendar, in order to schedule events or Google Meet events. However, in order to do so, you need to prompt your users to grant access to their respective scopes. Here, we’ll show you how to do that.
Workarise Meetings feature
To sync Workarise with your Google Calendar and obtain a Google Meet link, we developed a calendar using MUI. When you click on a day, a popover will appear with the option to schedule a meeting.
If you haven’t granted Workarise permissions to access your Google Calendar, it will prompt you to do so. This will redirect you to log in with Google and accept to give access only for your calendar. If you accept, you will be redirected to the Workarise app page, which will show that the authorization was successful.
This UX flow is necessary because Google needs to authenticate the user and only grant access when the user authorizes it. For this purpose, we created a little API with Node.js to manage this flow for Workarise, utilizing the Google OAuth2 API library.
Time to work
To get started, the first step is to create a project on Google Cloud Console. After creating the project, you can navigate to the "APIs & Services" tab by clicking on the hamburger menu or using the search bar. From there, select "Enable APIs and Services." On the left sidebar, you'll find the "Credentials" tab. Click on it and then select "Create Credentials" > "OAuth Client ID" at the top of the page.
Select "Web application" as the Application type. Next, choose a name for your project and add the necessary links to authorize your project to use this client.
Once the client is created, open it and copy the Client ID and Client Secret. These keys will be necessary for future use.
The next step is to initialize a Node.js API, which can be done by creating a new directory.
mkdir google-oauth-api && cd google-oauth-api
Initialize npm
npm init -y
Change your scripts in the package.json
for these
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
Install dependencies
npm i cors express googleapis http https morgan nodemon
In the root folder, create a server.js
file
import express from 'express';
import morgan from 'morgan';
import cors from 'cors';
const app = express();
const port = process.env.PORT || 8000;
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(morgan('dev'));
app.use(
cors({
origin: ['http://localhost:3000'], // Here your app dev env/prod urls
})
);
app.use((req, res, next) => {
// set the CORS policy
res.header('Access-Control-Allow-Origin', '*');
// set the CORS headers
res.header(
'Access-Control-Allow-Headers',
'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers'
);
// set the CORS method headers
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'GET PATCH DELETE POST');
return res.status(200).json({});
}
next();
});
app.listen(port);
console.log(`Server listening on port ${port}`);
We will use Express, Morgan, and Cors to open a port to our endpoint and configure the CORS policy. Additionally, we will set the CORS method headers to enable access to our API from our web application.
To get started, navigate to the root directory and create a new directory named src/
. Inside this directory, create two additional directories named controllers/
and routes/
.
Within the controllers/
directory, create a new file named googleCalendar.controller.js
. This file will contain the necessary logic to interface with the Google Calendar API.
import { google } from 'googleapis';
const GOOGLE_CLIENT_ID =
'YOUR_CLIENT_ID';
const GOOGLE_CLIENT_SECRET = 'YOUR_CLIENT_SECRET';
const oAuth2Client = new google.auth.OAuth2(
GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET,
'http://localhost:8000' // The root of your API
);
const calendar = google.calendar({
version: 'v3',
auth: 'AIzaSyAzgIbwnyoa6eeyDpSNk-8V3aEee5ND4Lc',
});
const scopes = ['https://www.googleapis.com/auth/calendar'];
In this step, we will generate a login URL, which we will then send to your web application to be used inside an tag. It is important to set the access_type
to offline
in order to obtain a code.
export const generateAuthorizationUrl = async (req, res, next) => {
const authorizationUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true,
});
res.send({ url: authorizationUrl });
};
After the user confirms the scope access, you should redirect them to the root of the API in order to obtain a code in the URL parameters. Next, use the oAuth library to save that code and generate a refresh token. Finally, redirect the user to a specific route of your web app with the refresh token in the parameters. Once there, retrieve the refresh token and store it in your database, associated with the corresponding user.
export const redirect = async (req, res, next) => {
const { code } = req.query;
try {
oAuth2Client.getToken(code, (err, tokens) => {
if (err) {
console.log('server 39 | error', err);
throw new Error('Issue with Login', err.message);
}
const refreshToken = tokens.refresh_token; // <- Store it in your DB
// Change the slashes to something that don't breakes the URL
res.redirect(
`YOUR_WEB_APP_ROUTE${refreshToken.replace(/\//g,'%2F'
)}`
);
});
} catch (error) {
res.redirect('YOUR_WEB_APP_ROUTE');
}
};
Next, from your web application, you can send an event object with the necessary data to create an event in the user's Google Calendar. You can reference the required structure here.
To ensure that the user is not repeatedly prompted for authorization, be sure to use the previously created and stored refresh token. This will allow your application to access the user's Google Calendar data without requiring additional permission grants.
export const createEvent = async (req, res, next) => {
try {
const { refreshToken, event } = req.body;
oAuth2Client.setCredentials({
refresh_token: refreshToken,
});
const eventResponse = await calendar.events.insert({
auth: oAuth2Client,
calendarId: 'primary',
conferenceDataVersion: 1,
requestBody: event,
});
res.send({ data: eventResponse.data });
} catch (error) {
res.send({ error: error.message });
}
};
Awesome! With the event ID and refresh token, you can now edit or delete events within the user's Google Calendar. This provides greater flexibility and control over the events created by your application.
export const updateEvent = async (req, res, next) => {
const { refreshToken, eventID, event } = req.body;
oAuth2Client.setCredentials({
refresh_token: refreshToken,
});
try {
const updateResponse = await calendar.events.patch({
auth: oAuth2Client,
calendarId: 'primary',
eventId: eventID,
resource: event,
});
res.send({ data: updateResponse.data });
} catch (error) {
console.log(error);
res.send({ error: error.message });
}
};
export const deleteEvent = async (req, res, next) => {
const { refreshToken, eventID } = req.body;
oAuth2Client.setCredentials({
refresh_token: refreshToken,
});
try {
const deleteResponse = await calendar.events.delete({
auth: oAuth2Client,
calendarId: 'primary',
eventId: eventID,
});
res.send({ data: deleteResponse.data });
} catch (error) {
console.log(error);
res.send({ error: error.message });
}
};
Don’t forget to add the routes!
src/routes/googleCalendar.route.js
import { Router } from 'express';
import {
createEvent,
generateAuthorizationUrl,
redirect,
updateEvent,
deleteEvent,
} from '../controllers/googleCalendar.controller.js';
const googleOAuthRouter = Router();
googleOAuthRouter.get('/', redirect);
googleOAuthRouter.get('/generate-authorization-url', generateAuthorizationUrl);
googleOAuthRouter.post('/create-event', createEvent);
googleOAuthRouter.put('/update-event', updateEvent);
googleOAuthRouter.delete('/delete-event', deleteEvent);
export default googleOAuthRouter;
Top comments (0)