2.2.2 • Published 1 year ago

@adieolami/maigaurd v2.2.2

Weekly downloads
-
License
MIT
Repository
-
Last release
1 year ago

Gateman offers

  • Minimal overhead and complexity
  • Role based access control (RBAC) for services and authenticated users
  • Encryption and decryption of url safe encrypted tokens

Installation

Install via yarn

yarn add @random-guys/gateman

Install with NPM

npm install @random-guys/gateman

Introduction

Gateman allows you transform a Javascript object containing a particular role e.g user, admin and a user's id, into an encrypted cookie/URL/HTTP header friendly token with an integrity check. This allows you securely pass around this token without exposing the user's id and role.

Encrypted signed (integrity-checked) tokens allow you encrypt the role and id of the user contained within the token, pass this token around from client to server or server to server, without worrying about someone modifying (or even knowing) what those roles are. Any modification to the encrypted data will invalidate its integrity.

Gateman also provides an Express middleware for securing endpoints. This middleware guards against requests that do not contain signed encrypted tokens created by Gateman.

How it works

Encryption is done using the Iron library which uses AES256 for encryption and SHA256 for Integrity checks.

Gateman generates tokens for two main uses cases Client to Server and Server to Server

Client to Server

Gateman allows you create signed encrypted tokens that can be safely used for client to server communication. A typical instance is a token created and sent back to the client when a user logs in from an iOS or android app. This token is then subsequently used for communication between the app (client) and backend (server) until the token session expires.

When a token is created in this scenario the following assumptions and actions are taken:

  1. An object in the following format {id: some-unique-user-id, role: "user" | "admin"} is signed and encrypted, thus generating the token.
  2. The token is persisted to Redis for a fixed period of time (indicating the user's session)
  3. The Gateman library expects the Bearer authentication scheme to be used when sending the token from the client to server i.e it expects the following Authorization header Bearer <token>

Server to Server (Headless tokens)

server and services are used interchangebly

Gateman allows you create signed encrypted tokens that can be safely used for server to server communication. Imagine a scenario in a microservice architecture where a particular service service A performs a cronjob by 2am every day, which makes an API request to another service service B on the behalf of a particular user. This API request is headless in the sense that an authenticated user does not trigger it directly. We would need a way to get the id of the user. as well as validating that only recognized services can call the API endpoint that fulfills the request.

Gateman specifically caters to this scenario by creating headless tokens that contain the name of the source service and can also decode and validate that the token was sent from a recognized service.

When a token is created in this scenario the following assumptions and actions are taken:

  1. An object in the following format { id: some-unqiue-user-id, role: 'service', service: some-service-name } is signed and encrypted, thus generating the token.
  2. The token is created with a short Time-to-live (TTL) of 60 seconds i.e the token is only valid for 1 minute, after which subsequent requests made with it would fail.
  3. The Gateman library expects a custom authentication scheme to be used when sending the token from the client to server i.e it expects the following Authorization header <Custom scheme> <token>. This custom authentication scheme is passed when creating a new instance of Gateman.

API

new Gateman({ service: string, authScheme: string, redis: IRedisService, secret: string, sessionDuration?: number })

Creates a new Gateman instance where:

  • service Name of the service initializing Gateman
  • authScheme Custom authentication scheme used for service to service calls
  • redis Redis instance object
  • secret Secret key used for encryption and integrity signing. Should be at least 32 characters
  • sessionDuration How long tokens should be peristed to Redis in seconds. Defaults to 600 seconds i.e 10 minutes
import { Gateman } from "@random-guys/gateman";

const gateman = new Gateman({
  service: "service-name",
  authScheme: "Customscheme",
  redis: RedisClient,
  secret: "9b2e051cf4e90bc86dcd128184fc7614",
  sessionDuration: 180,
});

persistSession(id, token, sessionDuration)

Persists a token using the user's id in Redis for a specific period of time. Stores the token and user's id as a key value pair, where the user's id is the key and the token is the value in Redis. You typically do not need to call this directly, call createSession instead.

  • id The user's id
  • token The user's encrypted token
  • sessionDuration How long the token should be peristed to Redis in seconds. Overwrites the session duration provided in the constructor. If it is not provided it defaults to the session duration provided in the constructor
await gateman.persistSession(
  "51c2168c-00f6-4e9a-becb-6274ae9fa5d9",
  "Fe26.2**a03bffbf883a555e953afe7d524ed30da778bd5a4747141c40fd9a0e3c2a63f7*9rarsXkWp9TvymsXB7oTiQ*ifTyoXxOHEH4cArCcjKBEY4fA5vK6tSStfagGVuy2GqMSSa4BybLKtZY4JXKFQ5ARLACuY-oEDx7ybqIdPLDLoDHZrxNzSBYUIm-4Capj1I*1561642137848*845cbd2a8beb578138ddb626eafe3b384b96ee7b6c8d88cd27e95053a375ec96*K7QBSsEi54ZaPXz5DABQ8MrYhqW181ivFiblXZ00GKs",
  100
);

clearSession(id)

Deletes a token from Redis using the user's id

  • id The user's id
await gateman.clearSession("51c2168c-00f6-4e9a-becb-6274ae9fa5d9");

createSession(id, role, sessionDuration)

Creates and returns an encrypted token using the user's id and role, and persists it to Redis for a specific period of time. Used for creating admin and user sessions. Calls persistSession internally to persist the tokens.

  • id The user's id
  • role The user's role. Defaults to user
  • sessionDuration How long the token should be peristed to Redis in seconds. Overwrites the session duration provided in the constructor. If it is not provided it defaults to the session duration provided in the constructor
const token = await gateman.createSession(
  "51c2168c-00f6-4e9a-becb-6274ae9fa5d9",
  "user",
  120
);

createHeadlessToken(id)

Creates a token that can be used for headless (i.e not triggered by a human user) inter-service calls by encrypting the service name and the id of the user whom the call is made for. The token is not persisted. The token is not persisted instead a TTL is attached to the token, after the which the token would be invalidated.

  • id The user's id
const token = await gateman.createHeadlessToken(
  "51c2168c-00f6-4e9a-becb-6274ae9fa5d9"
);

guard(roles, service)

Returns an Express middleware that guards requests to a particular endpoint using the token in the Authorization header against recognized roles.

  • roles The role(s) allowed to call the endpoint, defaults to user. Should be either user or admin. An array can be provided if multiple roles can call the endpoint e.g ['user', 'admin', 'service']
  • service The optional service(s) allowed to call the endpoint. roles should either contain or be service when this argument is provided. An array can provided if multiple services can call the endpoint e.g ['wallets', 'cards'] If service is "*" all services can call the endpoint
// User guard
app.post("/albums", gateman.guard("user"), routeHandler);

// Admin guard
app.put("/albums", gateman.guard("admin"), routeHandler);

Examples

The following examples show how Gateman can be used for securing endpoints for various use cases

Callable by only users

app.get("/user", gateman.guard("user"), routeHandler);

// Same as above because the default role is `user`
app.get("/default", gateman.guard(), routeHandler);

Callable by only admins

app.get("/admin", gateman.guard("admin"), routeHandler);

Callable by only a specific service

// Only allows headless calls by the wallet service
app.get("/service", gateman.guard("service", "wallet"), routeHandler);

Callable by specific multiple services

// Only allows headless calls by the wallet and transaction service
app.get(
  "/service",
  gateman.guard("service", ["wallet", "transaction"]),
  routeHandler
);

Callable by all services

// Only allows headless calls by all services
app.get("/service", gateman.guard("service", "*"), routeHandler);

Callable by users and a specific service

app.get(
  "/user-and-service",
  gateman.guard(["user", "service"], "wallets"),
  routeHandler
);

Callable by users and multiple services

app.get(
  "/user-and-multiple-services",
  gateman.guard(["user", "service"], ["transactions", "trips"]),
  routeHandler
);
2.2.1

1 year ago

2.2.2

1 year ago

2.2.0

1 year ago

2.1.5

2 years ago

2.1.8

1 year ago

2.1.7

1 year ago

2.1.9

1 year ago

2.1.4

2 years ago

2.1.3

2 years ago

2.1.1

3 years ago

2.1.0

3 years ago