npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

simple-google-openid

v0.4.1

Published

A simple library for using Google as the authenticator of your application's users.

Downloads

7

Readme

node-simple-google-openid

This is a simple library providing two Express.js middlewares for using Google as the authenticator of your application's users.

All authentication workflows are done in the client's browser; to authenticate with a server, the browser sends a JSON Web Token to your server's API.

In the server, this package will add req.user structured like a Passport User Profile.

This package makes use of Google Auth Library.

Status

  • works for me, does what I need
  • let me know if it doesn't work for you or if you'd like any new functionality

Installation

npm install simple-google-openid

Usage

Express middleware for authentication

First, this package provides an Express.js middleware that will take an ID token from the URL query (parameter id_token) or from a bearer token (HTTP header Authorization: Bearer TOKEN).

To add the middleware to your app, you need to give it your CLIENT_ID (see Create a Google Developers Console project and client ID). A full working example is included below.

const GoogleAuth = require('simple-google-openid');

…

app.use(GoogleAuth(CLIENT_ID));

If an ID token is found and successfully parsed, the middleware will add req.user like Passport User Profile.

How to require authentication

To require authentication for a part of your app (e.g. /api/*), you can use the guardMiddleware; this will ensure that the app returns 401 Unauthorized on requests without an authentication token.

app.use('/api', GoogleAuth.guardMiddleware());

This package does not provide any authorization – guardMiddleware lets in any signed-in Google user. Your app needs to provide authorization logic.

Use outside of Express.js

To get a token from the Authorization header in an HTTP request, you can use the getAuthToken() function:

const token = getAuthToken(req);

Then to verify it, read on.

Verifying tokens

If you get ID tokens with getAuthToken() or some other way outside of the Authorization header (e.g. as part of WebSocket messages), you can verify them and get the user information using the verifyToken() function that returns a Promise.

Using await/async:

const auth = GoogleAuth(CLIENT_ID);

…

const token = ...; // get token from somewhere
const user = await auth.verifyToken(token);
if (!user) ...; // token was not valid (e.g. expired)

Using .then():

const auth = GoogleAuth(CLIENT_ID);

…

const token = ...; // get token from somewhere
auth.verifyToken(token)
  .then((user) => {
    if (!user) ...; // token was not valid (e.g. expired)
  });

Minimal skeleton of an authenticated web page

Here's what we need to do in a web page to get the user authenticated. This follows a guide from Google: Integrating Google Sign-In into your web app. A full working example is included further down on this page.

<!doctype html>
<title>TITLE</title>

<!-- this loads google libraries -->
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="CLIENT_ID">

<!-- this puts a sign-in button, and a sign-out link, in the page -->
<div class="g-signin2" data-onsuccess="onSignIn"></div>
<p><a href="#" onclick="signOut();">Sign out</a></p>

<!-- this shows how the page can use the information of the authenticated user -->
<script>
function onSignIn(googleUser) {
  // do something with the user profile
}

async function signOut() {
  await gapi.auth2.getAuthInstance().signOut();
  // update your page to show the user's logged out, or redirect elsewhere
}

// example that uses a server API and passes it a bearer token
async function callServer() {
  const id_token = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse().id_token;

  const fetchOptions = {
    credentials: 'same-origin',
    method: 'GET',
    headers: { 'Authorization': 'Bearer ' + id_token },
  };
  const response = await fetch(API_ENDPOINT_URL, fetchOptions);
  if (!response.ok) {
    // handle the error
    return;
  }
  // handle the response
}

// see the complete example below for an extra function that refreshes the token when the computer wakes up from a sleep
</script>

Example

Here's a full working example. First, the server that implements an API that needs to securely know users' email addresses; second, the client side.

Server-side

A full working server (server.js) follows:

const express = require('express');
const app = express();

const GoogleAuth = require('simple-google-openid');

// you can put your client ID here
app.use(GoogleAuth(process.env.GOOGLE_CLIENT_ID));

// return 'Not authorized' if we don't have a user
app.use('/api', GoogleAuth.guardMiddleware());

app.get('/api/hello', (req, res) => {
  res.send('Hello ' + (req.user.displayName || 'user without a name') + '!');

  console.log('successful authenticated request by ' + req.user.emails[0].value);
});

// this will serve the HTML file shown below
app.use(express.static('static'));

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`Example app listening on port ${PORT}!`);
});

Save this file as server.js and run it with your client ID like this:

npm init -y
npm install express simple-google-openid
GOOGLE_CLIENT_ID='XXXX...' node server.js

Client-side – the web page in a browser

Now let's make a Web page (static/index.html) that authenticates with Google and uses the API above. Save this file in static/index.html, start the server above, and go to http://localhost:8080/.

This follows a guide from Google: Integrating Google Sign-In into your web app.

Don't forget to replace CLIENT_ID (on line 4) with your own client ID.

<!doctype html>
<title>Simple Google Auth test</title>
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="CLIENT_ID">


<h1>Simple Google Auth test <span id="greeting"></span></h1>

<p>Press the button below to sign in:</p>
<div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div>
<p><a href="#" onclick="signOut();">Sign out</a></p>

<p>Below is the response from the server API: <button onclick="callServer()">refresh</button>
<pre id="server-response" style="border: 1px dashed black; min-width: 10em; min-height: 1em; padding: .5em;"></pre>

<script>
function onSignIn(googleUser) {
  const profile = googleUser.getBasicProfile();
  const el = document.getElementById('greeting');
  el.textContent = '– Hello ' + profile.getName() + '!';

  setTimeout(callServer, 100);
}
async function signOut() {
  await gapi.auth2.getAuthInstance().signOut();
  console.log('User signed out.');
  const el = document.getElementById('greeting');
  el.textContent = 'Bye!';
}

async function callServer() {
  const token = gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse().id_token;

  const el = document.getElementById('server-response');
  el.textContent = 'loading…';

  const fetchOptions = {
    credentials: 'same-origin',
    method: 'GET',
    headers: { 'Authorization': 'Bearer ' + token },
  };
  const response = await fetch('/api/hello', fetchOptions);
  if (!response.ok) {
    // handle the error
    el.textContent = "Server error:\n" + response.status;
    return;
  }

  // handle the response
  const data = await response.text();
  console.log('setting text content: ' + data);
  el.textContent = data;
}

// react to computer sleeps, get a new token; gapi doesn't do this reliably
// adapted from http://stackoverflow.com/questions/4079115/can-any-desktop-browsers-detect-when-the-computer-resumes-from-sleep/4080174#4080174
(function () {
  const CHECK_DELAY = 2000;
  let lastTime = Date.now();

  setInterval(() => {
    const currentTime = Date.now();
    if (currentTime > (lastTime + CHECK_DELAY*2)) {  // ignore small delays
      gapi.auth2.getAuthInstance().currentUser.get().reloadAuthResponse();
    }
    lastTime = currentTime;
  }, CHECK_DELAY);
}());
</script>

Logging

To enable logging into console output, set the environment variable DEBUG to a non-empty string.

TODO

  • tokens might be retrieved from POSTed form data as well, maybe
  • use https://www.npmjs.com/package/express-bearer-token
  • tests

Author

Jacek Kopecky

License

This project is licensed under the MIT license. See the LICENSE file for more info.