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

reqsign

v1.1.0

Published

HTTP request signing

Downloads

5

Readme

reqsign

js-semistandard-style

HTTP request signing

This is a simplified and opinionated HTTP request signing scheme for use in communication between HTTP APIs.

The module provides both the server middleware and client functionality.

Installation

$ npm install reqsign --save

Usage

Server-side

const app = require('express')();
const bodyParser = require('body-parser-of-your-choice');
const reqsign = require('reqsign');

const reqsignOptions = {
  clockSkew: 300,
  keyRetriever (login) {...},
  replayAttackDefender (login, signature) {...}
};

// Mount the middleware
app.use(bodyParser());
app.use(reqsign.server(reqsignOptions));

// Use it
app.get('/some_path', (req, res) => {
  const isRequestAuthenticated = req.user.isAuthenticated;
  const userLogin = req.user.login;
  // etc
});

Client-side

const reqsign = require('reqsign');

const reqsignOptions = {
  login: 'my_service_login',
  key: 'secret'
};

const req = reqsign.client(reqsignOptions);

const data = {
  prop1: 'value1',
  prop2: 'value2'
};

req.post('url', data)
.then(response => {
  // Make use of response.resStatus and response.resBody
})
.catch(err => {
  // Process the err gracefully
});

Scheme Description

Get and store current TimeStamp

TimeStamp = GET-TIMESTAMP()

TimeStamp is the current system time UNIX timestamp of the client machine including milliseconds (e.g., 1465564560647).

Build String To Sign

The client has to build the StringToSign following the following pattern:

StringToSign = <TimeStamp> + "\n" + <ContentString>

<ContentString> is a string formed depending of the request type.

If the request contains any payload (Content-Length HTTP header is present and its value is greater than 0), ContentString = MD5(<PayloadRawString>).

If the request contains no payload (Content-Length HTTP header is not present or its value is 0), the ContentString is formed using the following algorithm:

  • All URL query parameters are sorted in alphabetical order ascending.
ContentString =
  URI-ENCODE(<QueryParameter1>) + "=" + URI-ENCODE(<value>) + "&" +
  URI-ENCODE(<QueryParameter2>) + "=" + URI-ENCODE(<value>) + "&" +
  ...
  URI-ENCODE(<QueryParameterN>) + "=" + URI-ENCODE(<value>)

Sign the StringToSign

Signature = BASE64(HMAC-SHA256(<StringToSign>, <key>))

<key> is a secret key shared between the client and the server.

Send Authorization header

The client sends the Authorization HTTP header with the request:

Authorization: Signature timestamp={Int} login={String} signature={String}

Server-side middleware

Options

The options object:

{
  "clockSkew": "{Integer}",
  "keyRetriever": "{Function}",
  "replayAttackDefender": "{Function}"
}

{Integer} clockSkew

A clock skew value in seconds that compensate possible differences between the server and client machines system time. The clock skew is applied in both directions (e.g., clockSkew = 300s means 300s in the past AND 300s to the future).

It is not feasible to set this parameter to 0 or a very small value as in this case all requests will be treated as expired. Hence, the default value is 300, and the minimum value is 60.

{Function} keyRetriever (login)

A function that retrieves the secret key for the given login value that the client uses to sign requests. Mechanism of storing the login-key pairs is out of scope for reqsign.

Parameters:

  • {String} login - The login value sent by the client in Authorization HTTP header.

Returns {Promise} resolve(result), reject(err):

  • {String | Object | null} result - If result is a String, this is the key associated with the login to be used to verify the signature. If result is an Object, it must have the following properties:

    • {String} key;
    • {Array<String>} roles - a collection of roles associated with the login;
  • {Error} err - An error object. Note that absence of a key for given login is not an error condition - in this situation the promise has to resolve with the null value.

{Function} replayAttackDefender (login, signature)

OPTIONAL. A function that might be used to protect the server against the Replay Attack. The implementation of protection (what the function does) is out of scope for reqsign.

Parameters:

  • {String} login - Login value derived from the Authorization header;
  • {String} signature - Signature value derived from the Authorization header.

Returns: {Promise} resolve(isOk) reject(err):

  • {Boolean} isOk - true if the request is not replayed; otherwise - false;
  • {Error} err - An error object.

API

reqsign middleware extends the req object with user property and passes the request down the middleware pipe.

  • {Boolean} req.user.isAuthenticated

  • {String} req.user.login

  • {Array<String>} req.user.roles

  • {String | null} req.user.errorCode - Error code as follows:

    • WRONG_REQUEST - The request received does not comply with the scheme (e.g., wrong format of the Authorization header, or its absence etc).
    • NO_KEY - A key to verify the signature.
    • EXPIRED - The request expired.
    • WRONG_SIGNATURE - Signature verification failed.
    • REPLAYED - The request is replayed.

Client module

Use a function returned by reqsign.client(options) call to make signed HTTP requests to third-party APIs.

Options

The options object:

{
  "login": "{String}",
  "key": "{String}"
}

{String} login

The login your application is registered with by a third-party API.

{String} key

The key/password shard by your application and a third-party API.

API

{Function} reqsign.client(options)

Returns an instance of the API client you use to make signed HTTP requests to APIs.

const reqsign = require('reqsign');
const opts = {
  login: 'my_login',
  key: 'shared_key'
};
const req = reqsign(opts);

{Function} req.get(url, data)

Method to make a GET request.

Parameters:

  • {String} url - Target URL (without query parameters).
  • {Object} data - Data to be sent in request parameters.

Return: Promise<Object> - Promise that resolves with an object with properties:

  • {Integer} resStatus - Response HTTP status code.
  • {Any} resBody - Response payload.

{Function} req.post(url, data)

Method to make a POST request.

Parameters:

  • {String} url - Target URL (without query parameters).
  • {Object} data - Data to be sent as a JSON object in request body.

Return: Promise<Object> - Promise that resolves with an object with properties:

  • {Integer} resStatus - Response HTTP status code.
  • {Any} resBody - Response payload.