Numeric Production Mechanism

    @brainhubeu/hadron-auth

    0.0.2 • Public • Published

    Installation

    npm install @brainhubeu/hadron-auth --save

    Overview

    hadron-auth provides back-end authorization layer for routes You will choose.

    Configuration with Hadron Core

    If You want to use hadron-auth with hadron-core You should also use hadron-typeorm and hadron-express. All You need to provide is two schemas for typeorm:

    • User (id, username, and roles many-to-many relation required) Here is the example schema:
    // schemas/User
    const userSchema = {
      name: 'User',
      columns: {
        id: {
          primary: true,
          type: 'int',
          generated: true,
        },
        username: {
          type: 'varchar',
          unique: true,
        },
        passwordHash: {
          type: 'varchar',
        },
        addedOn: {
          type: 'timestamp',
        },
      },
      relations: {
        roles: {
          target: 'Role',
          type: 'many-to-many',
          joinTable: {
            name: 'user_role',
          },
          onDelete: 'CASCADE',
        },
      },
    };
    
    module.exports = userSchema;
    • Role (id and name required) Example schema:
    // schemas/Role
    const roleSchema = {
      name: 'Role',
      columns: {
        id: {
          primary: true,
          type: 'int',
          generated: true,
        },
        name: {
          type: 'varchar',
          unique: true,
        },
        addedOn: {
          type: 'timestamp',
        },
      },
    };
    
    module.exports = roleSchema;

    Don't forget to add schemas to Your database config, example below:

    // config/db.js
    const userSchema = require('../schemas/User');
    const roleSchema = require('../schemas/Role');
    
    const connection = {
      name: 'mysql-connection',
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'my-secret-pw',
      database: 'done-it',
      entitySchemas: [roleSchema, userSchema],
      synchronize: true,
    };
    
    module.exports = connection,

    Now You need to prepare Your hadron configuration file, where You can add secured routes, for example:

    // index.js
    const config = {
      routes: {
        helloWorldRoute: {
          path: '/',
          methods: ['GET'],
          callback: () => 'Hello World',
        },
        adminRoute: {
          path: '/admin',
          methods: ['GET'],
          callback: () => 'Hello Admin',
        },
        userRoute: {
          path: '/user',
          methods: ['GET'],
          callback: () => 'Hello User',
        },
      },
      securedRoutes: [
        {
          path: '/admin/*',
          methods: ['GET', 'POST', 'PUT', 'DELETE'],
          roles: 'Admin',
        },
        {
          path: '/user/*',
          roles: ['Admin', 'User'],
        },
      ],
    };

    Finally You need to add hadron-auth to hadron initialization method:

    const hadron = require('@brainhubeu/hadron-core').default;
    const hadronExpress = require('@brainhubeu/hadron-express');
    const hadronTypeOrm = require('@brainhubeu/hadron-typeorm');
    const hadronAuth = require('@brainhubeu/hadron-auth');
    const express = require('express');
    
    const expressApp = express();
    
    const hadronInit = async () => {
      const config = {
        routes: {
          helloWorldRoute: {
            path: '/',
            methods: ['GET'],
            callback: () => 'Hello World',
          },
          adminRoute: {
            path: '/admin',
            methods: ['GET'],
            callback: () => 'Hello Admin',
          },
          userRoute: {
            path: '/user',
            methods: ['GET'],
            callback: () => 'Hello User',
          },
        },
        securedRoutes: [
          {
            path: '/admin/*',
            methods: ['GET', 'POST', 'PUT', 'DELETE'],
            roles: 'Admin',
          },
          {
            path: '/user/*',
            roles: ['Admin', 'User'],
          },
        ],
      };
    
      const container = await hadron(
        expressApp,
        [hadronAuth, hadronExpress, hadronTypeOrm],
        config,
      );
    };

    Warning, You should pass hadronAuth as first to hadron packages array.


    Now Your routes are secured, by default, hadron-auth authorize user by JWT Token, passed as Authorization header.

    Creating custom auth middleware

    You can pass Your own function in hadron configuration to check if a user is authorized to the secured route. Here is the skeleton for the authorization middleware:

    const authorizationMiddleware = (container) => {
      return (req, res, next) => {};
    };

    hadron-auth provides isAllowed function, to check if a user is allowed to specified route:

    isAllowed(path, method, user, allRoles);

    Where:

    • path - path to secured route, for example /api/admin/1
    • method - HTTP method
    • user - User object, which need to contain roles
    • allRoles - All roles stored in database (only role names)

    Here is an example authorization middleware:

    const jwt = require('jsonwebtoken');
    const { isRouteSecure, isAllowed } = require('@brainhubeu/hadron-auth');
    
    const errorResponse = {
      message: 'Unauthorized',
    };
    
    const expressMiddlewareAuthorization = (container) => {
      return async (req, res, next) => {
        try {
          if (!isRouteSecure(req.path)) {
            return next();
          }
    
          const userRepository = container.take('userRepository');
          const roleRepository = container.take('roleRepository');
    
          const token = req.headers.authorization;
    
          const decoded: any = jwt.decode(token);
    
          const user = await userRepository.findOne({
            where: { id: decoded.id },
            relations: ['roles'],
          });
    
          if (!user) {
            return res.status(403).json({ error: errorResponse });
          }
    
          const allRoles = await roleRepository.find();
    
          if (
            isAllowed(req.path, req.method, user, allRoles.map((role) => role.name))
          ) {
            return next();
          }
    
          return res.status(403).json({ error: errorResponse });
        } catch (error) {
          return res.status(403).json({ error: errorResponse });
        }
      };
    };
    
    module.exports = expressMiddlewareAuthorization;

    To use it, You need to pass an expressMiddlewareAuthorization function as authorizationMiddleware key in hadron config.

    const config = {
      authorizationMiddleware: YourCustomFunction,
    };

    Usage:

    const securedRoutes = [
      {
        path: '/api/**',
        methods: ['GET'],
        roles: ['Admin', 'User'],
      },
      {
        path: '/api/**',
        methods: ['POST', 'PUT', 'DELETE'],
        roles: 'Admin',
      },
      {
        path: '/admin/*',
        roles: 'Admin',
      },
      {
        path: 'product/info',
        methods: ['GET'],
        roles: [['Admin', 'User'], 'Manager'],
      },
    ];
    • Path - here we can specify the route path we want to secure, we can use a static path like /api/admin/tasks or by pattern:
      • /api/admin/* - route after /api/admin/ is secured, for example /api/admin/tasks - is secured, but /api/admin/tasks/5 - will be not secured
      • /api/admin/** - every route after /api/admin is secured
    • methods - an array of strings, where You can pass role names, if You will not provide any role, then the route is secured and user with ANY role can access this if a user does not have any role he will be unauthorized.
    • roles - here You can pass single role name, an array of role names or array of arrays of strings, which add some logic functionality, for example, if we declare:
    roles[(['Admin', 'User'], 'Manager')];

    The user needs Admin AND User OR Manager role to access the route.

    Install

    npm i @brainhubeu/hadron-auth

    DownloadsWeekly Downloads

    6

    Version

    0.0.2

    License

    MIT

    Unpacked Size

    74 kB

    Total Files

    33

    Last publish

    Collaborators

    • benedyktdryl
    • dluber
    • brainhubeu-devops
    • annalach
    • szymon.morawski
    • dyoda
    • brainhubeu-ci
    • roberthebel