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

hades-auth

v1.0.61

Published

Authentication libraries are typically very messy. Usually they're terrible to start off with, too cramped and don't solve a problem enough to be worth using. Most developers resort to session keys / bearer tokens because it's the easiest. This library ai

Downloads

103

Readme

About

Authentication libraries are typically very messy. Usually they're terrible to start off with, too cramped and don't solve a problem enough to be worth using. Most developers resort to session keys / bearer tokens because it's the easiest. This library aims to change that by making public / private key signing authentication easier than session / bearer tokens.

Why should I be using public/private key signing for authentication? Session keys / bearer tokens are weak because if someone intercepts them, they can use them. With public / private key signing and correct implementation, if someone were to intercept your request, they would only to be able to resend the request you just signed (and that can be stopped with nonces and signing) and can't use the authentication for whatever they want. With session / bearer tokens, if someone intercepts your request, they can take that token and use it to the full extent it's authorized.

If your database is leaked, with session keys / bearer tokens, it comes down to your hashing methods and handling of that data in your database, including if someone had gotten into a webserver/load-balancer and started collecting tokens. With public / private key signing, you're only storing public-keys on your end and they're called "public-keys" for a reason, because it doesn't matter if they're leaked.

Generate credentials (client-side)

import { generate_new_credentials } from "hades-auth";

const credentials = await generate_new_credentials();

// credentials.private_key - Store this locally and **NEVER** allow it to leave the device. Avoid storing it in cookies, because cookies, in some configurations, are sent to the server by your browser, and you need to make sure that doesn't happen.

// credentials.public_key - Send this to the server, it's public, and it doesn't matter if this is leaked. That's why public/private key authentication is so amazing. If you're database is leaked, provided the attacker didn't modify anything, your logged-in devices don't need to be reset.

Verify the credentials are up to standard (server-side)

import { onboard_new_device } from "hades-auth";

// Webserver logic here, such as taking a POST request with the public-key.
try {
    const verification = await onboard_new_device(body.public_key);
    
    // verification.deviceid - for your convenience, a deviceid is generated by Authenticator, however, you can easily disregard it and use your own identifier.
} catch (error) {
    console.log("Invalid", error);
    
    // Respond to the client with an error message that their key is not up to standard.
}

// Add logic for storing the public-key in your database, and respond to the client with 200 status and a deviceid you can use in the future to match it with the stored public-key.

Use fetch_wrapper to seamlessly sign requests (client-side)

import { fetch_wrapper } from "hades-auth";

let device_id = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

// Normally you'd get this from local storage or elsewhere.
let private_key = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAvH5WytTrfNHtfmJ0heMDotHBQXFR7jYx1rAZYpa0fNJcDeYIMV+mUjM/9ujMK4aaqwaxN1Viw2Ku/zlfKCJj3O2hgYkDgYYABADAKAtlhXvMXArHWxDt3IrUoVFndTyCjiSyteJwSVvd5VLr1hXVTZ9VJHOpSxq+Ght2LWaqIBShQfT4th/vzroypgBNSnkf+dH1bqiSaT01tznAoKwSqfxBgdRspJxCmYd87ukf/KB/INrZ7XX+4/pAT9Q8NqQEctS/DHrg/dRIUyEmNg==
-----END PRIVATE KEY-----`;

// pstttt, if you're using expressjs with JSON parsing middleware, you need to set "Content-Type" to be "application/json" when sending JSON, otherwise it errors and thinks there is an empty body. A little annoying quirk of expressjs.
const response = fetch_wrapper(`https://example.com`, {
    method: 'POST',
    mode: 'cors',
    cache: 'default',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
        name: "John Doe"
    }),
    redirect: 'error',
}device_id, private_key)

Sign data (client-side)

import { sign } from "hades-auth";

let metadata = {
    deviceid: ''
    // whatever you want here!
}

// You should think of metadata like URL params and the body object as well...a body. They're seperate because metadata is _always_ json, which makes it easy to pass something like an image in the body and not need to mold additional data like the deviceid into that formdata. They're seperate because data formatting can get quite messy and it's absolutely better to have the 2 seperate values. Here are some example bodies, but you can use what you want!

let formData = new FormData();
formData.set("a", "1");
formData.set("b", "2");
formData.set("c", "3");
let body = formData.toString();

let body1 = {
    a: "1",
    b: "2",
    c: "3"
}

let body3 = "SSB3YW50ZWQgdG8gcHV0IGFuIGltYWdlIG9yIGEgcXVvdGUgaGVyZSwgYnV0IGJvdGggc3RyaW5ncyB3b3VsZCBoYXZlIGJlZW4gdG9vIGxvbmcuIEFueXdheSwgbmljZSB0byBzZWUgeW91J3JlIGVuam95aW5nIHRoZSBjb2RlYmFzZSBlbm91Z2ggdG8gcGVhayBiZWhpbmQgdGhlIGN1cnRhaW4gOik=";

// Normally you'd get this from local storage or elsewhere.
let private_key = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAvH5WytTrfNHtfmJ0heMDotHBQXFR7jYx1rAZYpa0fNJcDeYIMV+mUjM/9ujMK4aaqwaxN1Viw2Ku/zlfKCJj3O2hgYkDgYYABADAKAtlhXvMXArHWxDt3IrUoVFndTyCjiSyteJwSVvd5VLr1hXVTZ9VJHOpSxq+Ght2LWaqIBShQfT4th/vzroypgBNSnkf+dH1bqiSaT01tznAoKwSqfxBgdRspJxCmYd87ukf/KB/INrZ7XX+4/pAT9Q8NqQEctS/DHrg/dRIUyEmNg==
-----END PRIVATE KEY-----`;

const jwt = await sign(metadata, body, private_key);

// Send this JWT to your server.

Authenticate data (server-side)

import { authenticate } from "hades-auth";

let body = // get incoming body from your webserver as an object (not a JSON string).
let params = new URLSearchParams(); // Don't panic about params! If you're not planning on sending data in traditional means, such as an HTTPS request, you can leave this as an empty string and just use the body param.

// Normally you'd get this from local storage or elsewhere.
let private_key = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAvH5WytTrfNHtfmJ0heMDotHBQXFR7jYx1rAZYpa0fNJcDeYIMV+mUjM/9ujMK4aaqwaxN1Viw2Ku/zlfKCJj3O2hgYkDgYYABADAKAtlhXvMXArHWxDt3IrUoVFndTyCjiSyteJwSVvd5VLr1hXVTZ9VJHOpSxq+Ght2LWaqIBShQfT4th/vzroypgBNSnkf+dH1bqiSaT01tznAoKwSqfxBgdRspJxCmYd87ukf/KB/INrZ7XX+4/pAT9Q8NqQEctS/DHrg/dRIUyEmNg==
-----END PRIVATE KEY-----`;
let pathname = // get pathname from your webserver. Hint: If you're using expressjs, it's req.path :)

// body: the incoming body of your request, as an object (not a json string).
// params: incoming URL params, formatted as a params string, such as "?a=1&b=2&c=3";
// jwt: jwt generated from fetch-wrapper() or sign(). If you used fetch_wrapper, in POST requests you can find it in your request body with the key "authenticator_JWT_Token", and for everything else as a param with the key "authenticator_JWT_Token".
// pathname: The pathname of the incoming request. Fetch_wrapper signs the request pathname (and if you're using sign(), you should also be adding a body.authenticator_pathname or params.authenticator_pathname key) and you'll need to specify the pathname for authentication to be successful.

try {
    const authentication = await authenticate(body, params.toString(), jwt, public_key, pathname); // returns true if successful.
} catch (error) {
    // Authentication failed.
}