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

node-makerpass

v1.4.1

Published

A library to conveniently access the MakerPass API

Downloads

379

Readme

node-makerpass

First install:

$ npm install --save node-makerpass

Then require it in your node app:

var MP = require('node-makerpass');

Authentication (AuthN)

There are three ways to protect your endpoints behind a MakerPass auth: via sessions, a header, or directly.

For any of the following auths, you can pass in required: false to allow the request to continue if the user is not signed in. This allows signed-out users to visit your endpoints. For example:

MP.authWithSession({ required: false })

Session AuthN

The authWithSession middleware works particularly well if you are storing your MakerPass OAuth access token inside a session (similar to the example shown here):

app.post('/comments', MP.authWithSession(), function (req, res) {

  req.makerpassToken //=> token stored here to normalize between different auths

  req.user   //=> { uid, name, email, avatar_url }
  req.scopes //=> ['public', 'profile.basic', ...]

  res.send(`Welcome, ${req.user.name}!`);
});

//
// Additional options:
//

// This will read req.session.accessToken
MP.authWithSession();
// Same as above
MP.authWithSession({ name: 'session', propName: 'accessToken' });

// This will read req.mySession.accessToken
MP.authWithSession({ name: 'mySession' });

// This will read req.session.mpToken
MP.authWithSession({ propName: 'mpToken' });

// You can also specify a redirect on failure
MP.authWithSession({ redirectOnFailure: '/' })

Header AuthN

If your client is sending a MakerPass OAuth access token via the Authorization header, you can auto-check for that using authWithBearer:

//
// This works if a client sends a request with header that looks like:
// 'Authorization': 'Bearer myToken123'
//
app.post('/comments', MP.authWithBearer(), function (req, res) {

  req.makerpassToken //=> token stored here to normalize between different auths

  req.user   //=> { uid, name, email, avatar_url }
  req.scopes //=> ['public', 'profile.basic', ...]

  res.send(`Welcome, ${req.user.name}!`);
});

Multi-AuthN

If you want to enable both session and header auth, you can use authWithBearerOrSession:

//
// This works if a client sends a request with header that looks like:
// 'Authorization': 'Bearer myToken123'
//
app.post('/comments',
  //
  // The Authorization header will takes priority.
  // The redirectOnFailure option only applies when there is no Bearer token.
  //
  MP.authWithBearerOrSession({ redirectOnFailure: '/' }),

  function (req, res) {

    req.makerpassToken //=> token stored here to normalize between different auths

    req.user   //=> { uid, name, email, avatar_url }
    req.scopes //=> ['public', 'profile.basic', ...]

    res.send(`Welcome, ${req.user.name}!`);
  }
);

Direct AuthN

If you already have access to your token, or want to do things manually, you can use authToken:

MP.authToken(myAccessToken)
  .then(function(response) {
    response.data.user   //=> { uid, name, email, avatar_url }
    response.data.scopes //=> ['public', 'profile.basic', ...]
  })
  .catch(function(errResponse) {
    errResponse.status //=> 401, etc.
    errResponse.data   //=> 'the_error_message'
  });

Authorization (AuthZ)

Scope Validation

You can control access by requiring certain scopes from your user's accessToken. For example:

app.get(
  '/admin/dashboard',
  MP.authWithSession(),
  MP.requireScope('admin.read'),
  function (req, res) {
    res.send("You have admin-level read access.")
  }
)

Group Memberships Validation

MP.requireMembership is a convenient gate for ensuring your oauth user is a member of the group. By default, this also passes for any school admin of that group. You can provide { allowSchoolAdmins: false } as the last argument to disable this.

This middleware requires either group_id or group_uid to be defined in req.params.

app.post(
  '/groups/:group_id/chats',
  MP.authWithBearerOrSession(),

  MP.requireMembership('instructor', 'fellow'),
  // MP.requireMembership('instructor', 'fellow', { allowSchoolAdmins: false }),

  function (req, res) {
    console.log("You are a a fellow or instructor of the group")
  }
)

User Access Validation

MP.requireUserConnection ensures that the oauth user has a valid connection to the user in question. Note that if the oauth user is an admin of the target user's school, this passes by default.

You can specify which key to use in req.params; user_uid is used by default.

//
// Example #1: Validate oauth user is instructor of the student
//            OR oauth user is an admin of a school (with ANY role) the student is a member of.
//
MP.requireUserConnection({ role: 'instructor' })

//
// Example #2: Validate oauth user is instructor OR fellow of the student
//            OR oauth user is an admin of a school (with ANY role) the student is a member of.
//
MP.requireUserConnection({ role: ['instructor', 'fellow'], paramKey: 'uid' })

//
// Example #3: Validate oauth user is instructor of student,
//             AND NOT ALLOWING any school admins
//
MP.requireUserConnection({ role: 'instructor', schoolAdminRole: false })

//
// Example #4: Validate oauth user is a school admin **owner** (other option is 'collaborator')
//
MP.requireUserConnection({ schoolAdminRole: 'owner' })

API methods

Assuming you have already an accessToken obtained from e.g. passport-makerpass, you can request MakerPass data like the following:

MP.me(myAccessToken)
  .then(function (user) {
    console.log("You access token belongs to", user.name);
  });

The following methods are available:

  • MP.me.groups(myAccessToken) - Get all groups for owner of access token

  • MP.me.groupAccess(nameId, myAccessToken) - Get level of access information for a particular group

  • MP.me.schools(myAccessToken) - Get all schools for owner of access token

  • MP.me.adminStatus(myAccessToken) - Get all groups and schools you currently admin

  • MP.user(userUid, myAccessToken) - Get information for a specific user

  • MP.user.groups(userUid, myAccessToken) - Get all groups for a specific user

  • MP.group(nameId, myAccessToken) - Get information for a group. Note: A name id is a string. For example: mks-24

  • MP.group.memberships(nameId, myAccessToken) - Get all memberships for a group. See note above about name ids

Manual URLs

If you find a MakerPass API URL that is not supported by this lib, no need to wait; you can make requests manually:

MP.Memberships.get('/some/future/url', myAccessToken)
  .then(function (data) {
    console.log("You got the data:", data);
  });

Testing

When you're testing your own API endpoints, it's useful to mock the client's user and scopes. You can do this by setting the environment variable NODE_ENV=test and adding a middleware that explicitly sets the user and scopes properties on the request object:

process.env.NODE_ENV = 'test';
var express = require('express');
var request = require('supertest-as-promised');

var AdminAPI = require('../server/apis/admin-api.js');

describe("My API", function () {

  var currentUser   = null;
  var currentScopes = null;

  var testApp = express()

  // Set req.user and req.scopes on every request
  testApp.use(function (req, res, next) {
    req.user   = currentUser;
    req.scopes = currentUser;
  })

  testApp.use('/admin', AdminAPI)

  beforeEach(function () {
    // Reset to standard values before every test
    currentUser   = { name: 'Alice', uid: 'alice' };
    currentScopes = ['public', 'admin.read'];
  })

  it("requires admin.read scope", function () {
    currentScopes = ['public']
    return request(testApp)
      .get('/admin/dashboard')
      .expect(403)
  })

  it("returns dashboard data", function () {
    return request(testApp)
      .get('/admin/dashboard')
      .expect(200)
  })

})