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

@narando/authorization

v0.36.0

Published

Opinionated authorization framework with Promises based on narando architecture.

Downloads

72

Readme

@narando/authorization

Opinionated authorization framework with Promises based on narando architecture.

Getting Started

You need to have nodejs and npm installed.

$ npm install @narando/authorization

Usage

Activities take the form service:scope:method:item, eg.: api:articles:get:list. A Permission is an Activity that is linked to a user and contains additional information:

// Permission
{
  // Name of Activity
  "name": "service:scope:method:item",
  // Wether this permission only applies to objects that
  // the user owns/has control of.
  "onlyAssociated": true
}

To create an instance of the authorization module you have to invoke authorize

import Authorization from "@narando/toolkit";
import model from "app/model";

// You can preconfigure options for the authorization.
// If you are in a specific express controller the scope
// of all checked permissions is usually the same, so you
// can set it once and then only need to overwrite it if it
// differs.
const auth = Authorization.authorize({ scope: "articles" });

// Now you can use the auth object to perform different kinds of
// authorization

await auth.action({
  method: "get",
  item: "list",
  user: req.user,
});

// This will throw if the user does not have to required permissions for this activity

Express Middleware

// You can also use the express middleware to allow/deny access to parts of the interface
import express from "express";

const app = express();

app.use(
  auth.middleware({
    /* ... */
  })
);

app.get("/restricted", (req, res) => {
  /* ... */
});
// This will either call the next middleware if the user has sufficient permission
// or send a response with the appropriate HTTP response code associated to the
// thrown error as defined in @narando/errors

Decorator

If you have a function and you want to restrict access to it, you can use the decorator pattern.

To use it you have to have the babel plugin babel-plugin-transform-decorators-legacy installed and configured.

@auth.decorate({
  method: 'get',
  item: 'list'
})
function getArticles(req) {
  /* ... */
}

This will either throw on the invocation of the method if the user does not have sufficient permissions, or call the decorated function if he does.

Association Checks

In some cases a black/white authorization strategy might be insufficient. A user might have access to his own articles, but not to articles created by other users. For these cases you can supply the auth method with a model class and a model instance that will be queried for the association with the user.

These checks are only executed if the matching user permission has the flag onlyAssociated: true. This allows administrators to bypass them, while normal users will be stopped.

With a Model

When you have not yet found the instance of the requested resource, but want to restrict access to the controller, you can set the model for the check in the options:

@auth.decorate({
  method: 'get',
  item: 'list',
  model: model.Article // { isAssociated: async ({ reqParams, user }) => boolean }
})
function getArticles(req) {
  /* ... */
}

If the user has a permission with the right activity (api:articles:get:list here) and a flag onlyAssociated: true, the Authorization module will call the method async model.isAssociated({reqParams, user}) => boolean that you have to implement. This method will get the path parameters and the user that is making the request.

As the naming of the path parameters is up to the service it can be quite inconsistent for different routes, so a one-size-fits-all implementation of this variant is quite hard. The alternative is, to use the instance based checks.

With an Instance

When you already have the instance, or you do not want to rely on the path parameters you can can use the instance based association check. As with the model based association check you have to supply the instance to the authorization check:

await auth.action({
  method: 'put',
  item: 'item',
  user: req.user,
  instance: article // { isAssociated: async ({ user }) => boolean }
})

article.update(newArticle);

Similar to the model based asssociation check, if the user has a permission with the right activity (api:articles:put:item here) and a flag onlyAssociated: true, the Authorization module will call the method async instance.isAssociated({user}) => boolean that you have to implement. This method will receive the user that is making the request and is expected to return true if the user is associated and false otherwise.

Disable association checks

Association checks are enabled by default (disableAssociationCheck: false). If you wish to disable it you can pass disableAssociationCheck with a value of true via the options and it will ignore association checks. Examples are below.

@auth.decorate({
  method: 'get',
  item: 'list',
  disableAssociationCheck: true
})
function getArticles(req) {
  /* ... */
}
await auth.action({
  method: 'put',
  item: 'item',
  disableAssociationCheck: true
})

article.update(newArticle);
const auth = Authorization.authorize({
  scope: "job",
  disableAssociationCheck: true
});

Development

As this package is part of the toolkit monorepo, please refer to the top-level README to learn about hacking on this package.

Built With

  • @narando/errors - Collection of semantic errors