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 🙏

© 2026 – Pkg Stats / Ryan Hefner

sentri

v5.2.2

Published

Auth/authorization library for Express, Fastify, Hono, and Elysia — PostgreSQL + JWT

Readme

Sentri

npm version license build

Sentri is a comprehensive, production-ready authentication and authorization library designed for modern Node.js ecosystems. It provides seamless integration with Express, Fastify, Hono, Elysia, and Koa. Sentri is engineered to handle complex identity requirements, including role-based access control (RBAC), attribute-based access control (ABAC), session management, idempotency, and multi-identifier login systems (e.g., email, phone number, username).

Sentri operates in two distinct modes to accommodate diverse architectural needs:

  • Server Mode: Functions as a fully-featured, standalone authentication server. It leverages Kysely for automatic database schema management, issues standard JSON Web Tokens (JWTs), maintains active session state, and exposes out-of-the-box endpoints for user registration, login, token rotation, and public key discovery (SSO).
  • Client Mode: Designed for stateless microservices that require robust validation of JWTs issued by the Sentri Server. Client Mode automatically fetches and caches public keys from the server, eliminating the need for direct database connectivity while maintaining strict security standards.

Supported Frameworks & Exports

| Import Path | Description | | ---------------- | --------------------------------------------------------------------------- | | sentri | Core functionality and framework-agnostic utilities. | | sentri/core | Core types, configurations, SentriError, and SentriLogger. | | sentri/express | Express.js adapter (createAuthExpress, middleware, routing). | | sentri/fastify | Fastify adapter (createAuthFastify, hooks, and plugin). | | sentri/hono | Hono adapter (createAuthHono, middleware, routing). | | sentri/elysia | Elysia adapter (createAuthElysia, middleware, routing). | | sentri/koa | Koa adapter (createAuthKoa, middleware, routing). |


Table of Contents

  1. Installation
  2. Quick Start Guides
  3. Architecture Overview
  4. Server Mode Configurations
  5. Client Mode Integrations
  6. Single Sign-On (SSO) Capabilities
  7. Multi-Identifier System
  8. Idempotency & Rate Limiting
  9. Middleware Reference
  10. REST Endpoints
  11. Error Handling & Customization

Installation

Install Sentri via NPM:

npm install sentri

Sentri bundles kysely natively, alleviating the need for separate query builder installations. However, you must install the specific driver corresponding to your relational database system.

PostgreSQL (Recommended):

npm install pg

MySQL / SQLite:

npm install mysql2
npm install better-sqlite3

Framework Peer Dependencies: Install the framework you intend to use Sentri with:

# Express
npm install express

# Fastify
npm install fastify @fastify/cookie

# Hono
npm install hono

# Elysia
npm install elysia

# Koa
npm install koa @koa/router koa-bodyparser

Quick Start Guides

Express.js Integration (Server Mode)

import express from "express";
import { createAuthExpress } from "sentri/express";
import { PostgresDialect } from "kysely";
import pg from "pg";

const { Pool } = pg;

// 1. Initialize the Auth Server
const auth = createAuthExpress({
  mode: "server",
  validRoles: ["member", "administrator"] as const,
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL! }),
  }),
});

const app = express();
app.use(express.json());

// 2. Apply Idempotency Middleware (Optional but recommended)
app.use(auth.idempotencyMiddleware());

// 3. Execute Database Migrations (Safe to run on every startup)
await auth.migrate();

// 4. Mount the Authentication Router
app.use("/auth", auth.router());

// 5. Implement Protected Routes
app.get("/api/profile", auth.protect(), (req, res) => {
  res.json(req.user); // req.user is guaranteed to be populated here
});

// 6. Mount the Global Error Handler
app.use(auth.errorHandler());

app.listen(3000, () => console.log("Sentri Express Server is operational."));

Fastify Integration (Server Mode)

import Fastify from "fastify";
import cookie from "@fastify/cookie";
import { createAuthFastify } from "sentri/fastify";
import { PostgresDialect } from "kysely";
import pg from "pg";

const { Pool } = pg;

const auth = createAuthFastify({
  mode: "server",
  validRoles: ["member", "administrator"] as const,
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL! }),
  }),
});

await auth.migrate();

const app = Fastify();
await app.register(cookie);

// Register Sentri plugin encapsulating all endpoints
await app.register(auth.plugin(), { prefix: "/auth" });
app.setErrorHandler(auth.errorHandler());

app.get("/api/profile", { preHandler: auth.protect() }, async (request, reply) => {
  reply.send(request.user);
});

await app.listen({ port: 3000 });

Single Sign-On (SSO) Capabilities

Sentri facilitates seamless Single Sign-On across distributed systems. By leveraging asymmetric cryptography (RS256), the Central Authentication Server can distribute public keys dynamically to microservices.

The SSO Flow

  1. Authentication: The client authenticates via POST /auth/login on the Auth Server and receives a signed JWT access token.
  2. Resource Request: The client requests a protected resource from an independent Microservice (operating in Sentri Client Mode) using the Authorization: Bearer <token> header.
  3. Stateless Verification: The Microservice fetches the public key from the Auth Server via GET /auth/keys (cached automatically) and cryptographically verifies the token's validity and integrity without establishing a database connection.

Multi-Identifier System

Sentri discards the traditional single-identifier constraints. Users can register and authenticate using an arbitrary number of unique identifiers (e.g., email, phone number, corporate username).

All identifier values are enforced to be globally unique across the system, preventing account conflicts.

Bulk Identifier Management via API

Identifiers can be managed dynamically utilizing the built-in REST endpoints or the programmatic API.

// Add new identifiers to an existing user
await auth.bulkCreateIdentifiers(userId, [
  { type: "phone", value: "+1234567890" }
]);

// Update existing identifiers
await auth.bulkUpdateIdentifiers(userId, [
  { type: "email", value: "[email protected]" }
]);

Idempotency & Rate Limiting

Request Idempotency

Sentri includes robust idempotency middleware to prevent duplicate processing of non-idempotent operations (e.g., POST, PUT, PATCH) arising from network retries.

Clients provide an X-Idempotency-Key header. Sentri captures the response and serves it instantaneously on subsequent requests sharing the identical key. This feature can leverage Redis for distributed environments.

// Enable idempotency globally or on specific routes
app.use(auth.idempotencyMiddleware({
  ttl: 300_000, // Cache duration in milliseconds
  redisUrl: process.env.REDIS_URL, // Optional: Distributed caching
}));

Rate Limiting

Protect endpoints from brute-force attacks and abuse by implementing granular rate limiting.

app.post(
  "/api/secure-action",
  auth.rateLimiter({ maxAttempts: 5, durationSeconds: 60, keyPrefix: "secure-action" }),
  actionHandler
);

API Key Bypass (Machine-to-Machine)

Sentri natively supports authentication and authorization bypass via the X-Api-Key header for trusted server-to-server communication. When a valid API Key is provided (configured in AuthConfig via the apiKey property), the request will instantly bypass protect(), authorize(), and permit() checks without requiring a JWT token or active session.

// Configure the API Key during initialization
const auth = createAuthExpress({
  // ...other options
  apiKey: process.env.SENTRI_API_KEY // e.g. "sk_test_12345"
});

Note: Requests using an API Key will not have a `req.user` object populated, but they will be fully permitted through guarded routes.


Middleware Reference

Sentri provides highly composable middleware functions to enforce security policies at the route level.

  • auth.protect(): Validates the JWT access token (via Bearer header or Cookie) and populates the request context with the authenticated user data. Initiates silent token rotation if applicable.
  • auth.authorize(...roles): Implements Role-Based Access Control (RBAC). Rejects the request with a 403 FORBIDDEN if the authenticated user lacks at least one of the specified roles. Must be chained after protect().
  • auth.permit(checkFunction | options): Enables Attribute-Based Access Control (ABAC) and custom validation logic.

Advanced Permission Checks (ABAC)

app.delete(
  "/api/documents/:id",
  auth.protect(),
  auth.permit({
    roles: ["administrator"], // Administrators bypass the custom check
    check: async (req) => {
      // Execute business logic to verify ownership
      const document = await database.documents.findById(req.params.id);
      return document?.ownerId === req.user!.id;
    },
  }),
  deleteDocumentHandler
);

REST Endpoints

When auth.router() (or equivalent) is mounted, Sentri exposes the following endpoints:

| HTTP Method | Route Endpoint | Authorization | Description | | ----------- | ----------------------------- | -------------- | --------------------------------------------------------------------------- | | GET | /keys | Public | Exposes the JWKS public key set (Requires RS256 configuration). | | POST | /register | Public | Registers a new user. Supports X-Api-Key protection. | | POST | /login | Public | Authenticates user and issues Access & Refresh Tokens. | | POST | /refresh | Refresh Token | Rotates the refresh token and issues a new access token. | | POST | /logout | Refresh Token | Terminates the current active session. | | POST | /logout-all | Access Token | Revokes all active sessions across all devices for the user. | | GET | /me | Access Token | Retrieves the comprehensive profile of the authenticated user. |

Note: Endpoints ending in /identifiers (e.g., PUT /me/identifiers, PATCH /users/:userId/identifiers) expect the request body to be a valid JSON Array ([...]), not an Object.

| GET | /me/identifiers | Access Token | Lists all registered identifiers for the authenticated user. | | POST | /me/identifiers | Access Token | Registers additional identifiers in bulk. | | PUT | /me/identifiers | Access Token | Modifies existing identifiers in bulk. | | DELETE | /me/identifiers | Access Token | Removes identifiers in bulk (minimum one required). | | PATCH | /me/password | Access Token | Updates the user's password and revokes all active sessions. | | POST | /users/:userId/roles | Administrators | Assigns roles to a specified user. | | DELETE | /users/:userId | API Key | Deletes a user completely, cascading to all sessions and identifiers. | | PATCH | /users/:userId/identifiers | API Key | Admin: Modifies a user's existing identifiers in bulk. | | PATCH | /users/:userId/password | API Key | Admin: Updates a user's password and revokes all active sessions. | | POST | /bulk-register | API Key | Admin: Registers multiple users in bulk with configurable conflict handling.|


Error Handling & Customization

Sentri provides a universal Error Handler that transforms internal SentriError exceptions into standardized JSON responses complying with standard HTTP status codes.

app.use(auth.errorHandler({
  onUnhandled: (error) => {
    // Integrate with external logging services (e.g., Sentry, Datadog)
    logger.error("Unhandled Sentri exception:", error);
  }
}));

Custom Exception Throwing

You may utilize the SentriError class to throw domain-specific errors that will be seamlessly caught and formatted by the Sentri Error Handler.

import { SentriError } from "sentri/core";

export class ResourceNotFoundError extends SentriError {
  constructor(resourceName: string) {
    super("NOT_FOUND", `The requested resource '${resourceName}' could not be located.`, 404);
  }
}

Sentri is maintained by rizzzdev and released under the ISC License.