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

@nathangroup/authorize

v2.0.6-8

Published

a jwt authorize module

Downloads

78

Readme

Dependencies

This package uses jsonwebtoken, sqlite and express as dev dependencies and will install when you install the modules on installation. The package will also create a keys folder and generate the necessary private and public keys, it will also create a roles DB for you to use if need be

Implementation

const auth = require('@nathangroup/authorize')

You can also run the keys generator on the app.js or your index file so as to generate the relevant keys on server startup. The keys will only be generated once

The following is a sample implementation for the same

const { GenerateKeyPair } = require('@nathangroup/authorize');
GenerateKeyPair();

imports the module to your project.

Methods

IsAuthenticated - Checks for a token on the headers and authorizes a given route

GenerateToken("token string") - Generates a token with encrypted data

GenerateKeyPair() - Generates a key pair of public and private .pem files

EncryptText("encryption salt", "string to be encrypted") - Encrypts data over a custom algorithm

DecryptText("encryption salt", "string to be decrypted") - Decrypts data which have been encrypted using the EncryptText method

keyEncrypt("string to be encrypted") - Encrypts data using private and public keys

keyDecrypt("string to be decrypted") - Decrypts data using private and public keys

RoleAuthenticated - Authenticates a user based on a given role

createRole({ /* role Object */ }) - creates a role in the database. The route anticipates an object containing

    {
        name: "name of the role", permissions: [
            { "name": "frontend-route",
            "permissions": { "read": true, write: true },
            "contains": [ "route-name e.g users" ]}], id
    }

getAllRoles - returns all the roles in the database

updateRole({ /* object of what is to be updated */ }) - updates a role in the database. The route anticipates an object containing

{ name: "name of the role", permissions: [], id: 1 /* role id being updated */ }

the permissions are optional but the id and name are a must

getRoleById(id) - Return a single role by the id as parsed in the parameter

deleteRole(id) - deletes a given role in the DB, the ID parameters are a must

getServerSavedRoles - This route gives you all the roles saved in the server sqlite db

IsLocalAuthenticated - this method authenticates a Nathan digital token and can be used in place of IsAuthenticated when local tokens are used

VerifyNathanToken - this method is used to verify the token if you feel the need to verify the token then use the data there to create a middleware

GenerateNathanToken() - this method generates a nathan digital token. payload are a required field. The payload can be a string or a an object, the rest expiry, type are optional fields. Without the expiry the token will be valid for 1 year, the data type should be a date object, we advice using Date() objects that are in javascript. The type is a string showing which type the token is, i.e is it ana access or a refresh token. ps - this token is meant to be issued by Nathan and Nathan group

routesList(app) - this gives all the routes in the application, you can pass the app or routes in the parameters and it will give all the routes in the app

    app.get("/all-routes", (req, res) => {
        const data = routesList(routes, { prefix: "/v1" });
        res.status(200).json({ data });
    });

check if token is valid

auth.IsAuthenticated when applied to a route takes you next or gives you an error e.g

router.get("/home",auth.IsAuthenticated, myHomePage)

this will check for the Authorization token in the headers and check if it accepts tokens of type

Bearer, Api_key, Refresh, Access

generate tokens

auth.GenerateToken('token content as a string', 'expiry as a string')

the expiry could be in days, hours, minutes etc e.g 1d for one day etc. The generate token will create a keys folder in the parent folder which will contain two files a private and public .pem files if there is none. If there is one the module will use the available pem files to encrypt and decrypt data.

The token is a jwt encrypted with rs512 algorithm. The tokens contains a payload which has been encrypted and upon authentication the methods sets a res.user object based on the payload provided as decrypted.

Encryption and Decryption

The module can also be used for encryption and decryption by calling

auth.EncryptText('string to be encrypted')

and

auth.DecryptText('string to be decrypted')

and they both accept and return a string value. These encrypt and decrypt texts and they are not as strong encryption. These two encryption methods can also be used on the frontend in the case one needs to encrypt data while sending it to the server. The data encrypted must use the same package version so as to ensure the encryption and decryption is the same.

The other encryption methods are keyEncrypt and keyDecrypt which use the servers private and public keys to encrypt data. They can be used as

auth.keyEncrypt('string to be encrypted')

and

auth.keyDecrypt('string to be decrypted')

they will both return a string of the encrypted data and decrypted data respectively.

  Encrypt("string to be encrypted")
  Decrypt("string to be decrypted")

The above methods encrypt string through the crypto module. Their usage creates a new string containing encryption methods that are stronger than EncryptText and DecryptText. This is also the recommened method to use if one is to moce data in an encrypted format since this wont change even when we change the keys change

Keys generation

The module can generate keys by calling auth.GenerateKeyPair() this will generate a keys folder with a public and private .pem files which should not be pushed to a git repository.

req.user

the req.user object is set and should be an object parsed as a string preferably containing and any other fields needs

{_id: '', first_name: '', last_name: '', email: ''}

req.refresh

the req.refresh is set up when one is using the VerifyRefreshToken middleware ensuring and checking if the refresh token given is valid

{_id: '', first_name: '', last_name: '', email: ''}

Nathan Digital Token

Function:

GenerateNathanToken(payload, expiry, type)

Description

This function generates a Nathan token, which appears to be a custom token format used by "Nathan & Nathan Group". The token is encrypted using two encryption functions, keyEncrypt and Encrypt, which are assumed to be imported from a separate ./encryption module.

Parameters:

payload (object) - The data to be encoded in the token. This should be a JavaScript object or a string.

expiry (Date, optional) - The expiry time of the token. If not provided, the token will expire in one year.

type (string, optional) - The type of token (e.g., "Access Token", "Refresh Token"). Defaults to "Access Token".

Returns:

string The encrypted Nathan token.

Example Usage:

const payload = { user_id: 123, username: "johndoe" };
const token = auth.GenerateNathanToken(payload);
console.log(token);

Functions

VerifyNathanToken(token) - This function takes a token as input and verifies it. It checks the following things:

  1. The issuer of the token is "Nathan & Nathan Group"
  2. The token is not expired
  3. The token is properly formatted (has 3 parts separated by periods)
  4. If the token is valid, it returns the decoded payload of the token.

Otherwise, it returns an error message.

IsLocalAuthenticated(req, res, next)

This is a middleware function that can be used to protect routes in a Node.js application.

  1. It checks for a token in the Authorization header of the request.
  2. If a token is found, it calls the VerifyNathanToken function to verify it.
  3. If the token is valid, it adds the decoded payload of the token to the request object as the user property.
  4. If the token is invalid, it returns a 401 Unauthorized response to the client.
  5. If no token is found, it returns a 401 Unauthorized response to the client.

this method retrieves the token from the Authorization header of the request.

  • If there is no token, it returns a 401 Unauthorized response to the client.
  • If the token is present, it splits the token into an array of parts.
  • It checks the format of the token to make sure it has 3 parts separated by periods and that the first part is one of Bearer, Api_key or Token
  • If the token is valid, it adds the decoded payload of the token to the request object as the user property and calls the next function to continue processing the request.
  • If the token is invalid, it returns a 401 Unauthorized response to the client.

Role structure

for the roles to work you can call the auth.RoleAuthenticated method and the route will work as defined below. The super-admin role is created automatically and it has permission to all roles in the API.

The roles will be saved in an sqlite database so as to reduce the latency time and be incorporated int the tokens, this will enable the role to be checked when the token is being checked and only then shall the data be given back to the client. The roles have the freedom to be manipulated from the frontend as the user decides. The frontend team can create a page to change the permissions.

The package will create a new file named roles.model.js. This file will aid in saving the roles in mongoDb as the main storage but role verification will happen from the sqlite db that is created in the keys folder for speed and agility.

Please ensure that the user object in the users object has a role field that points to the roles collection in mongoDb, these keys will also be used in the backend when making queries to the sqlite support Db

    {
        "name": "super-admin",
        "permissions": [
            {
                "name": "dashboard",
                "permissions": {
                    "read": true,
                    write: true
                },
                "contains": [ "tasks", "profile" ]
            }
        ]
    }

This structure is checked when one is using a specific route.

The name of the role is the main identifier e.g a super-admin, sales consultant etc. The permissions array contains objects that determine if the given role is verified. the name in the object is the route as defined by the frontend team. E.g /home on the frontend, the permissions are boolean values of read and write, read will have the GET method and write will have the POST, PATCH and DELETE methods.

According to the MCS template each route is more or less like this

/v1/users/all-users

Roles are checked on the second value and in this case the users, this are the values that are in the contains array, if the array is empty then the algorithm will check for the route named as the name of the frontend route.

To have the roles work as intended please have the user Object contain a role key with the id of the said role in the database. e.g role: 1 for the said role linking the role to the user.

Dart & Frontend password encryption

The following code block works in encrypting data such as the login password and email. The idea is that the login should be encrypted to avoid MITM attacks on the login credentials.

ps the encryption strings should be the same on the API as well as on the frontend and mobile

The dart/flutter code

final String encryptionSalt = "use your new salt here";

String encodeText(String string) {
  List<int> encStr = utf8.encode(string);
  List<String> arrayFromString =
  encStr.map((point) => point.toRadixString(16)).toList();
  return arrayFromString.join("");
}

String encrypt(String salt, String text) {
  List<int> textToChars(String text) =>
      text.runes.toList(); // For Dart, String.runes returns the Unicode code points of the string.

  String byteHex(int n) => n.toRadixString(16).padLeft(2, '0');

  int applySaltToChar(int code) =>
      textToChars(salt).fold(code, (a, b) => a ^ b);

  return text
      .split('')
      .map((char) => textToChars(char)[0])
      .map(applySaltToChar)
      .map(byteHex)
      .join("");
}

String encryptText(String text) {
  String encodedText = encodeText(text);
  return encrypt(encryptionSalt, encodedText);
}

Frontend Usage

This package can be sparingly used in the frontend, some of the methods might not apply unless used in a server method i.e Nuxt server or Next server or even Sveltekit server. In the normal react, vue the tested working methods are the EncryptText() and the DecryptText() methods.

These methods used with a single salt between themselves and the backend can greatly aid in the encryption and decryption methods.

to use them you can use

import { EncryptText, DecryptText } from '@nathangroup/authorize';

// For encryption
EncryptText('salt', 'text to be encrypted');

// For decryption
DecryptText('salt', 'text to be decrypted');