Oauth 2.0 Connection: Google Calendar - Victorianuonuo/nudge_bot GitHub Wiki

Prerequisites

  1. GOOGLE_CLIENT_ID: Google API Credentials
  2. GOOGLE_CLIENT_SECRET: Google API Credentials
  3. DOMAIN: Your domain name

Instructions on how to get Google Calendar API key can be found here. The instructions also show why we need to deploy the app online and get a domain name for Google Calendar API.

Reference from Google Calendar API

Access process: OAuth 2.0

To allow users to get access from Slack, we need to use OAuth 2.0 to achieve so.

Trigger

There should be a starting point to allow users to begin the process. For our Slack chatbot, simply give users a button to click on to start the process.

function authenticate(slackID){
    bot.postMessage(slackID, 'Please click the following button to activate your account' , {
    as_user:true,
    "attachments": [
        {
            "fallback": "activate",
            "actions": [
                {
                    "type": "button",
                    "text": "connect",
                    "url": process.env.DOMAIN + '/apikey/googlecalendar/oauth?auth_id='+slackID
                }
            ]
        }
    ]
    });
}

This is a function to generate a link button in Slack chatbot. The Slack button format could be seen here. The url should be what you have defined in the Google API interface. In order to map each user's access token to their Slack IDs (slackID), we will add a new query after the url.

Oauth

router.get('/googlecalendar/oauth', function(req, res){
    var oauth2Client = new google.auth.OAuth2(
        process.env.GOOGLE_CLIENT_ID,
        process.env.GOOGLE_CLIENT_SECRET,
        process.env.DOMAIN + '/apikey/googlecalendar/connect/callback'
    )
    var url = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        prompt: 'consent',
        scope: [
            'https://www.googleapis.com/auth/userinfo.profile',
            'email',
            'https://www.googleapis.com/auth/calendar.readonly'
        ],
        state: encodeURIComponent(JSON.stringify({
            auth_id: req.query.auth_id
        }))
    });
    var slackID = req.query.auth_id;
    res.redirect(url);
})

Callback

router.get('/googlecalendar/connect/callback', function(req, res) {
    const code = req.query.code;
    var slackID = JSON.parse(decodeURIComponent(req.query.state)).auth_id;
    var oauth2Client = new google.auth.OAuth2(
        process.env.GOOGLE_CLIENT_ID,
        process.env.GOOGLE_CLIENT_SECRET,
        process.env.DOMAIN + '/apikey/googlecalendar/connect/callback'
    )
    oauth2Client.getToken(code, function (err, tokens) {
        if(err) {
            console.log(err);
        } else {
            //set credentials. not entirely sure what this does but necessary for google plus
            //when a person gives access to their google calendar, we also make a request to google plus
            //with their oauth2client in order to get their email address which is then saved in the user object
            //in mongodb.
            oauth2Client.setCredentials(tokens);
            var plus = google.plus('v1');
            plus.people.get({auth: oauth2Client, userId: 'me'}, function(err, person){
                if(err){
                    console.log(err);
                } else {
                    var tempEmail = person.data.emails[0].value;
                    let auth_id = JSON.parse(decodeURIComponent(req.query.state));
                    var newUser = new User({
                        token: tokens,
                        slackID: slackID,
                        auth_id: auth_id.auth_id,
                        email: tempEmail
                    });
                    newUser.save()
                    .then( () => {
                        res.status(200).send("Your account was successfuly authenticated");
                        bot.postMessage(slackID, "Congratulations! You are successfully connected to google calendar. Reminders for every day's events will come in at 7 am.", {as_user:true});
                        setTimeout(authenResuetime(slackID), 1000);
                    })
                    .catch((err) => {
                        res.status(400).json({error:err});
                        bot.postMessage(slackID, "Ooops!!! Error occurs! Please try again by saying Hi to me!", {as_user:true});
                    })
                }
            });
        }
    });
})