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

@aiyan/safeplaces-auth

v0.1.11

Published

The modular authentication service for the SafePlaces backend.

Downloads

22

Readme

SafePlaces Authentication Service

Build Status Coverage Status

The modular authentication service for the SafePlaces backend.

# Install using NPM
npm install @pathcheck/safeplaces-auth

# Install using Yarn
yarn add @pathcheck/safeplaces-auth

Table of Contents

Examples

Securing API endpoints

The authentication service can be instantiated and attached to an existing Express application. The point or order at which you attach the service relative to other middleware affects the point at which it is invoked.

const auth = require('@pathcheck/safeplaces-auth');

// Instantiate a public key retrieval client.
const pkClient = new auth.JWKSClient(
  // Pass the URL for the JWKS.
  `${process.env.AUTH0_BASE_URL}/.well-known/jwks.json`,
);

// Instantiate a request verification strategy.
const auth0Strategy = new auth.strategies.Auth0({
  jwksClient: pkClient,
  // The API audience is checked against the user's access token.
  apiAudience: process.env.AUTH0_API_AUDIENCE,
});

// Instantiate a strategy enforcer.
const enforcer = new auth.Enforcer({
  strategy: auth0Strategy,
  // Pass in an asynchronous database lookup function
  // that takes the user id as the only argument.
  userGetter: id => User.findOne(id),
});

// `app` is your Express application.
// A middleware is attached to the app, and it intercepts every
// request for verification. The argument to `enforcer.secure`
// affects which routes are secured.
enforcer.secure(app);

For greater flexibility, you access the built-in enforcer.handleRequest(req, res) function to selectively handle requests under your own logic. Note that enforcer will continue to end the request with 403 Forbidden if the request is unauthorized.

app.use((req, res, next) => {
  if (req.headers['X-Bypass-Login']) {
    return next();
  } else {
    return enforcer
      // Enforcer ends the request with a `403 Forbidden` if it is unauthorized,
      // meaning `next` will not be called unless the request is authorized.
      .handleRequest(req, res)
      .then(() => next())
      .catch(err => next(err));
  }
});

For the most flexibility, you can use enforcer.processRequest(req) to only validate a request, allowing you to decide how to handle the validation result yourself, whether that be ending the request or ignoring the error.

app.use((req, res, next) => {
  enforcer
    .processRequest(req)
    // `.then` is called only if `processRequest` has
    // determined the request to be authorized.
    .then(() => next())
    // Otherwise, an error describing the validation error
    // will be thrown, and you can decide what to do with it.
    .catch(err => res.status(403).send('Forbidden'));
});

Handling login requests

// Instantiate a login handler.
const loginHandler = new auth.handlers.Login({
  auth0: {
    baseUrl: process.env.AUTH0_BASE_URL,
    apiAudience: process.env.AUTH0_API_AUDIENCE,
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    realm: process.env.AUTH0_REALM,
  },
  cookie: {
    // Enable/disable cookie attributes depending on environment.
    secure: process.env.NODE_ENV !== 'development',
    sameSite: process.env.BYPASS_SAME_SITE !== 'true',
  },
});

// Handle all requests to the login endpoint.
// Since we are passing around the `handle` function, make sure
// to bind the handle function to its object.
app.post('/auth/login', loginHandler.handle.bind(loginHandler));

Handling logout requests

// Instantiate a logout handler.
const logoutHandler = new auth.handlers.Logout({
  redirect: 'https://example.com/logout-success/',
  cookie: {
    // Enable/disable cookie attributes depending on environment.
    secure: process.env.NODE_ENV !== 'development',
    sameSite: process.env.BYPASS_SAME_SITE !== 'true',
  },
});

// Handle all requests to the logout endpoint.
// Since we are passing around the `handle` function, make sure
// to bind the handle function to its object.
app.get('/auth/logout', logoutHandler.handle.bind(logoutHandler));

Strategies

Supported strategies:

  • Auth0 asymmetric JWT
  • Symmetric JWT

Auth0

Validate the JSON Web Token by checking the signature with the retrieved public key, and validate the API audience.

const auth = require('@pathcheck/safeplaces-auth');

const pkClient = new auth.JWKSClient(
  `${process.env.AUTH0_BASE_URL}/.well-known/jwks.json`,
);
const auth0Strategy = new auth.strategies.Auth0({
  jwksClient: pkClient,
  apiAudience: process.env.AUTH0_API_AUDIENCE,
});

Symmetric JWT

Validate the JSON Web Token by checking the signature with a fixed private key.

const auth = require('@pathcheck/safeplaces-auth');

const symJWTStrategy = new auth.strategies.SymJWT({
  algorithm: 'HS256',
  privateKey: process.env.JWT_SECRET,
});

Dynamic strategy selection

You can also pass a function into the strategy parameter to dynamically select the strategy based on the request or some other variables.

The function should accept the request as the only argument and return the desired strategy or a promise resolving the desired strategy.

const enforcer = new auth.Enforcer({
  strategy: req => {
    console.log(req);
    // Check something in the request.
    // ...
    // Example conditional:
    if (process.env.NODE_ENV === 'development') {
      return symJWTStrategy;
    } else {
      return auth0Strategy;
    }
  },
});

Debugging

To debug why the enforcer is rejecting a request, set the AUTH_LOGGING environment variable to verbose, and the request validation error will be logged every time.