1.0.8 • Published 2 years ago

@expraptor/security v1.0.8

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

@expraptor-security

@expraptor-security is a node.js package for securing an express application.

Installation

$ npm install @expraptor/security

Usage

Simple Usage (using session authentication with a memory user store)

import express from "express";
import session from "express-session";
import security from "@expraptor/security";

const port = 3000;
const app = express();
app.use(session({secret: "secret"}));
app.use(express.urlencoded());

const sec = security(app);
sec.buildAuth().inMemoryUser()
    .addUser("john", "john").withRoles("ADMIN").and()
    .addUser("jane", "jane").withAuthorities("CLIENT").and()
    .addUser("bob", "secret");

sec.httpSecurity().authorize()
    .requestMatcher("/client/(.*)").hasRole("ADMIN").hasAuthority("CLIENT")
    .and()
    .requestMatcher("/").permitAll()
    .anyRequest().authenticated();

app.get("/", (req, res) => {
    res.send("Welcome, no authentication needed.");
});
app.get("/resource", (req, res) => {
    res.send("Welcome, You're authenticated.");
});
app.get("/client", (req, res) => {
    res.send("Welcome, you have access to client.");
});

app.listen(port, () => {
    console.log(`server is listening on http://localhost:${port}`);
});

Custom User Authenticator (using session authentication with custom user authenticator)

interface UserAuthentication extends security.auth.Authentication {
    password: string;
}

class UserAuthenticator implements security.auth.Authenticator {

    private store: Record<string, UserAuthentication> = {
        paul: {
            id: 1,
            login: "paul",
            password: "paul",
            roles: [],
            authorities: []
        },
        bob: {
            id: 2,
            login: "bob",
            password: "secret",
            roles: [],
            authorities: []
        }
    };

    authenticate(login: string, password: string): security.auth.Authentication {
        /**
         * You can use a database call to get user
         */
        const user = this.store[login];
        if (user && user.password === password) {
            return user;
        }
        return undefined;
    }
}

sec.buildAuth().authenticator(new UserAuthenticator());

Stateless using WWW Basic Authentication

import express from "express";
import security from "@expraptor/security";

const app = express();
const sec = security(app);
sec.buildAuth()
    .basicAuthentication().realm("Basic Authentication App").and()
    .inMemoryUser()
    .addUser("john", "john").withRoles("ADMIN").and()
    .addUser("jane", "jane").withAuthorities("CLIENT").and()
    .addUser("bob", "secret");

Stateless using WWW Digest Authentication

import express from "express";
import security from "@expraptor/security";

const app = express();
const sec = security(app);
sec.buildAuth()
    .digestAuthentication().realm("Digest Authentication App").and()
    .inMemoryUser().digest()
    .addUser("john", "79fa2042db7866f3dbe977ef6be1df34").withRoles("ADMIN").and()
    .addUser("jane", "101e4095953a37653f29fe0a92ef3e04").withAuthorities("CLIENT").and()
    .addUser("bob", "92ba3d31cfb6c840bd41be8dbf057d89");
;

Stateless using JWT Token

First install jsonwebtoken

$ npm install jsonwebtoken

And

import express from "express";
import security from "@expraptor/security";

const app = express();
const port = 3000;
const sec = security(app);
sec.buildAuth().jwtTokenAuthentication("your-256-bit-secret");

sec.httpSecurity().authorize()
    .requestMatcher("/").permitAll()
    .anyRequest().authenticated();

app.get("/", (req, res) => {
    res.send("WELCOME HOME");
});
app.get("/resource", (req, res) => {
    res.send("You're authenticated");
});
app.listen(port, () => {
    console.log(`server is listening on http://localhost:${port}`);
});

Now to test this example got to https://jwt.io/ and generate a jwt using your-256-bit-secret and put this token in request Authorization header. You can use curl or postman or any http client to test this example.

Put Roles and Authorities

If you want to use roles and authorities in your Token, you have to define a JwtAuthorization to extract them from the decoded token. Suppose that your decoded token is

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "claims": {
    "roles": [
      "USER"
    ],
    "authorities": [
      "CLIENT"
    ]
  }
}

Then your JwtAuthorization

class JwtAuthorizationImpl implements security.auth.token.jwt.JwtAuthorization {

    getAuthorities(decoded: any): string[] {
        return decoded.claims.authorities;
    }

    getRoles(decoded: any): string[] {
        return decoded.claims.roles;
    }
}

sec.buildAuth().jwtTokenAuthentication("your-256-bit-secret")
    .jwtAuthorization(new JwtAuthorizationImpl());

sec.httpSecurity().authorize()
    .requestMatcher("/").permitAll()
    .requestMatcher("/admin").hasRole("ADMIN").and()
    .requestMatcher("/client/**").hasAuthority("CLIENT").and()
    .anyRequest().authenticated();

app.get("/", (req, res) => {
    res.send("WELCOME HOME");
});
app.get("/resource", (req, res) => {
    res.send("You're authenticated");
});
app.get("/admin", (req, res) => {
    res.send("You're admin");
});
app.get("/client", (req, res) => {
    res.send("You have CLIENT authority");
});
app.listen(port, () => {
    console.log(`server is listening on http://localhost:${port}`);
});