3
\$\begingroup\$

Trying to set up express server that will authenticate a user's Google email before proceeding.

The code below works, but is there any way to make it more elegant?

The whole new Promise thing feels clunky.

Still wrapping my head around async functions. All the googleapis functions are async, so I feel there's a better way.

I wanted to "wrap" the whole getEmail inside the app.get('/oauth2callback'... but I'm confused by how to "bubble up" a response from several levels of nested async calls so that the app.get call can send the final res to client (if that makes any sense.)

const { google } = require('googleapis');
const express = require('express');

const oauth2Client = new google.auth.OAuth2(
  oauthID, oauthSecret, // from google dev console
  "http://localhost:3000/oauth2callback" //callback URL
);

async function getEmail(auth, code) {
  const { tokens } = await oauth2Client.getToken(code)
  oauth2Client.setCredentials(tokens);
  return new Promise((resolve) => {
    google.people('v1').people.get(
      { auth: auth, resourceName: 'people/me', personFields: 'emailAddresses' },
      (err, res) => {
        if (err) { resolve(err) }
        email = res.data.emailAddresses && res.data.emailAddresses.length && res.data.emailAddresses[0].value
        resolve(email);
      }
    )
  });
}

const app = express();

app.get('/', async (req, res) => {
  const URL = await oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile']
  });
  res.send(`<a href="${URL}">login</a>`);
});

app.get('/oauth2callback', (req, res) => {
  getEmail(oauth2Client, req.query.code)
    .then(r => res.send('••Your Google email is: ' + r))
    .catch(e => res.send('••Error: ' + e))
})


app.listen(3000)

UPDATE: A few hours later, here's what I came up with:

const authURL = auth.generateAuthUrl({
  access_type: 'offline',
  scope: ['https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile']
});
//...
app.get('/oauth2callback', (req, res) => {
  auth.getToken(req.query.code)
    .then(r => {
      auth.setCredentials(r.tokens)
      google.people('v1').people.get(
        { auth: auth, resourceName: 'people/me', personFields: 'emailAddresses' }
      )
        .then(r => {
          email = r.data.emailAddresses && r.data.emailAddresses.length && r.data.emailAddresses[0].value;
          res.json({email: email})
        })
        .catch(e => res.send('••Error in people: ' + e))
    })
    .catch(e => {
      res.send(`Problem logging in, <a href="${authURL}">try again</a>`)
    })
})

This works, too ... but is it "better"?

\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.