Nothing makes me sweat like OAuth. Documentation is sparse and errors are cryptic. Libraries like Passport.js just add a poorly designed abstraction to an already difficult process. Does it have to be this hard? No.
Google authentication is actually pretty easy.
Google recently deprecated the old Google Plus API – so most google authentication guides are out of date. These days you’ll want to use the people.get endpoint.
Step 1. Get Credentials
First you need developer API credentials. Head over to the Google Developer Console and Create a New Project. Then go to your Project’s Dashboard and enable the Google People API. Now back to your project’s dashboard, click OAuth consent screen. Choose “External” and fill out the other info like website, company name, logo, etc.
Now go to the Credentials tab and click “Create Credentials > OAuth client ID”.
- App Type – Choose “Website”
- Authorized JavaScript origins – don’t include a path. For dev I use http://localhost:7777. For production use something like https://www.example.com
- Authorized redirect URIs – This should include the full URL that google will send the user back to. For example http://localhost:7777/google/callback for dev or https://www.example.com/google/callback for prod.
You should now have your Client ID and Client Secret.
Step 2. Install googleapis
Congrats… the worst is over. Now you need to install the googleapis npm package.
npm install --save googleapis
Step 3. Setup The Google Connection
For these last 3 steps, we’ll create create a file (I’m calling it google-routes.js) that will contain the two expressjs routes for implementing google authentication.
At the top of google-routes.js, we’ll need to setup an auth object that has our client id, secret, and redirect url:
import { google } from 'googleapis';
const buildAuth = function () {
return new google.auth.OAuth2(
'0000000000000-xxxxxxxx.apps.googleusercontent.com', // clientId
'XXXXXXXXXXXXXXXXXXX', // clientSecret
'http://localhost:7777/google/callback', // redirect
);
};
Step 4. Add the Login Route
In that same file, we’ll add a route for starting the login process. If a user wishes to login with Google, send them to /google/login and this route will redirect them to Google.
app.get('/google/login', async (req, res) => {
const auth = buildAuth();
const url = auth.generateAuthUrl({
access_type: 'offline',
prompt: 'consent',
scope: [
'https://www.googleapis.com/auth/userinfo.email',
'profile',
]
});
res.redirect(url);
});
So we build our auth client then generate an authentication url. You can add more scopes but you’ll need these two if you want their email address. Then redirect the user to that url. They will now see the Google login page.
Step 5. Handle Google’s Response
Once they login, google will send them back to the URL you provided twice. You entered it when you setup credentials and you entered it when you built the auth client in your code. Remember – those have to match exactly!
So the user logs in and google sends them back to your url but adds a query string parameter called “code”:
/google/callback?code=3/yQVdAynpi2RQ_z_vsvS6XrskZukZ8_eZ5mm2-YcgPihTzgwo96Sj37AA2FdGY3IUlic5IPn9TEqWmU_eSrAxaSY
You’ll take that code & exchange it for a token. Then you can use the token to load profile information that you listed in your scope. Here we fetch the emailAddresses property:
app.get('/google/callback', async (req, res) => {
// get & set tokens
const { code } = req.query;
const auth = buildAuth();
const { tokens } = await auth.getToken(code);
auth.setCredentials(tokens);
// fetch the user's email
const peopleApi = google.people({version: 'v1', auth}).people;
const me = await peopleApi.get({
resourceName: 'people/me',
personFields: 'emailAddresses',
});
const address = me.data.emailAddresses.find(e => e.metadata.primary);
const email = address && address.value;
// TODO: login with email
res.redirect('/');
});
You’ll need to implement the TODO portion – use the email address to find or create a user, then sign them in.
And that’s it! My entire google authentication implementation is 50 lines of code. Amazing!
See the complete google-routes.js source code at: https://gist.github.com/bendytree/e57868232eaf35271f0c83c9a57b1c2c