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

authgw

v1.0.3

Published

ExpressJS middleware to generate JWT auth tokens & provide user role management

Downloads

10

Readme

AuthGateway

Exposes an API to create user auth tokens based on the JWT spec and provides middleware plugins for user role access management on a route-by-route basis and for validating an auth token generated by this library.

  • currently only supports Express but could easily be extended for other formats

Usage

  const AuthGW = require('authgw');
  const app    = require('express')();
  const { TransportMethods, Flavors } = require('authgw');

  // set AuthGW configuration, library is stateful so only do this once
  let authgw = new AuthGW(
    // list of user roles, or null/empty if not using roles
    // it is important that the roles are ordered from lowest access level
    // to highest access level
    [ 'guest', 'user', 'admin' ],

    // issuer name, used to validate that a token came from a trusted source
    'myapp',

    // data schema, defines the data for what's written as into a token's
    // payload, required keys throw errors during validation when falsy
    [
      { name: "userid",   required: true  },
      { name: "username", required: false }
    ],

    // general options, defaults are shown
    {
      flavor: Flavors.EXPRESSJS, // the flavor of middleware to use, options found in lib/flavors.js
      tokenSecret: '<randomly generated>', // the secret key used to encrypt the tokens
      tokenExpiredCode: 419 // HTTP code to return if token is expired, 419 Session Timeout (unofficial) is the default

      // the transport is a wrapper around the method used to get the token
      // from a request, as well as putting the token into responses using
      // convenience methods
      transport: {
        method: TransportMethods.HEADER, // use headers for transporting tokens, options found in the TokenTransports enumeration
        key: 'x-access-token' // the 'key' to use when retrieving the token, in this case a header name
      }
    }
  );

  // tell our Express app to use the middleware generated by our configuration
  // this middleware will return 401 errors if a request contains an invalid
  // or expired auth token, otherwise it will write the data fields provided by
  // the data schema to the request object, returning 401 if the token does not
  // contain a data field marked "required" by the schema
  app.use(authgw.middleware());

  // we can use the Role Manager to lock down routes to a given list of roles,
  // these are handled on a route-by-route basis and it's highly recommended
  // to place the middleware declaration directly before the route definition,
  // though they can be declared anywhere as long as it's before the route def
  const RoleMgr = authgw.RoleManager;

  // only allow Admin users
  app.get('/supersecret', RoleMgr.restrictTo('admin'), (req, res) => { ... });

  // users and admins
  app.post('/myroute', RoleMgr.restrictTo(['user', 'admin']), (req, res) => { ... });

  // as the role lists get long and repetitive it's a good idea to start creating
  // named role groups using RoleManager#addRoleGrouping
  RoleMgr.addRoleGrouping('users', [ 'user', 'admin' ]);

  // RoleMgr.allowUsers() is now equiv. to RoleMgr.restrictTo(['user', 'admin'])
  app.get('/userstuff', RoleMgr.allowUsers(), (req, res) => { ... });

  // errbody
  app.get('/robots.txt', RoleMgr.allowAll(), (req, res) => { ... });
  // or
  app.get('/robots.txt', RoleMgr.restrictTo('*'), (req, res) => { ... });

  // create an auth token
  app.get('/signin', RoleMgr.allowAll(), (req, res) => {
    // get the data specified by the authgw configured data scheme
    let userData = { userid: req.body.userid, username: req.body.username };

    authgw.createToken(
      // data that is bundled w/ the token, will be injected into req when this
      // token goes through the middleware during a request
      userData,

      // role given to the token holder
      'user',

      // expiry of this token in minutes, expired tokens will be rejected by
      // the token verification middleware
      24 * 60
    )
    // inject the token into the response in any way you see fit
    .then(mytoken => res.send(mytoken))
    // or, use the authgw instance to inject the token according to the
    // rules set by the token transport settings
    .then(mytoken => authgw.injectToken(res, mytoken));
  });

Considerations

Beware the dreaded invalidation loop

It is vitally important that the client does not send another request with a token known to be invalid (i.e. your client has received the status code indicating session expiration or invalidation), or else the middleware will simply continue to send the error code – resulting in an infinite loop.

Randomly generated secrets

By default this library will make your JWT secret a random hex value generated from 24 random bytes (using Node's crypto library). This means that whenever your application restarts all tokens generated before the restart will now be invalid. Worse, if you use a round robin technique with multiple Node processes then the tokens will not be compatible between the instances. So it's highly recommended that you override this setting.

TODO:

  • make docs better, specifically add API docs
  • allow middleware to be configured to use extra claims as validation
  • remove dependency on underscore
  • remove dependency on Bluebird, use native Promises & allow it to be pluggable