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

mercutio

v1.0.0

Published

A module for rights management using roles and scopes

Downloads

27

Readme

Mercutio is a small module to validate user roles by scopes. It assumes an array of roles that can be described as [role]@[scope], where role is a non-hierarchical user type, and scopes are path-based domains of influence. Being admin@my/scope automatically implies that you are also admin@my/scope/area, but you have no status in @my.

Roles are not hierarchical. Being admin will not return true for any other role, so admin does not imply member, for instance.

const mercutio = require('mercutio');

const user = mercutio('admin@users/987');

user.is('admin@users/987'); // true, this is the main scope
user.is('admin@users/987/orgs/123'); // true, this is a sub-scope
user.in('users/987/myscope'); // true, this is a sub-scope
user.is('admin@users'); // false, this scope is above
user.is('member@users/987'); // false, member is NOT implied from admin

Mostly, a user will have several roles. You can also feed it arrays, and objects instead of strings:

let user = mercutio('admin@users/987', 'member@123');
user = mercutio(['admin@users/987', 'member@123']);
user = mercutio({ role: 'admin', scope: 'users/987' }, { role: 'member', scope: 'my/scope' });

Finally, it can also take and decode a JSON web token. But the decoded payload should have a roles property that is an array conforming to the above.

Express middleware

Mercutio exposes some middleware functions which can be used in an express compatible application. Please note that to use this, you need to require mercutio/express, which is an extended version with middleware functions. This version cannot be required on the frontend, as it relies on the jsonwebtoken package and verifies the token.

.identity middleware

This will augment the req object with a req.identity object, which contains

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

app.use(mercutio.identity());

app.use(function(req, res) {
	// true or false, based on whether a token was found and verified.
	const loggedIn = req.identity.authenticated;
	// ask if resolved user is admin in my/scope
	const isRole = req.identity.roles.is('admin@my/scope');
	// ask if user is in my/scope in any role
	const inScope = req.identity.roles.in('my/scope');
});

The req.identity object will have these properties:

{
	// decoded user object
	user: {},
	// whether a token was verified successfully
	authenticated: bool,
	// an initialized mercutio Roles object, created from roles on user object
	roles: { Mercutio object }
}

You can customize how mercutio gets the info necessary for constructing the identity. This is the options and their defaults:

app.use(mercutio.identity({
	// How to resolve the token
	tokenResolver: req => req.cookies.Authorization || req.get('Authorization') || null,

	// How to resolve the roles from the decoded token
	roleResolver: user => (user && user.roles) || [],
}));

.require middleware

This middleware will only work as expected if .identity was added earlier in the chain. It can be used to require a specific role as an access requirement to a route.

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

app.use(mercutio.identity());

// This will pass an `UnauthenticatedError` to next if the user is unauthenticated.
app.get('/admins', mercutio.require(), function(req, res) {});

// This will pass an `UnauthenticatedError` if no user, or an `InsufficientPermissionsError` if wrong role.
app.get('/admins', mercutio.require('admin@scope'), function(req, res) {});

// This will pass an `UnauthenticatedError` if no user, or an `InsufficientPermissionsError` if wrong role.
app.get('/secret-route', mercutio.require(req => `admin@users/${req.params.id}`), function(req, res) {});