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

@easyweb/authentication

v2.2.0

Published

Shared authentication primitives for Easyweb microservices: stateless JWT middleware, request context, and token verification helpers

Readme

@easyweb/authentication

Shared authentication primitives for Easyweb microservices — stateless JWT middleware, request-context middleware, and the token verification helpers services build on.

Companion to @easyweb/events for messaging, and @easyweb/errors for the HTTP error taxonomy.

2.1.0 — SUPER_ADMIN now satisfies authorize(["ADMIN"])

authorize() was an exact string match. Every admin route in the platform is written authorize(["ADMIN"]), and auth-service's admin-seed.ts grants the bootstrap operator SUPER_ADMIN by default — so the seeded account could not call a single admin route on the platform.

SUPER_ADMIN now implies ADMIN. Nothing else implies anything: ADMIN deliberately does not imply USER, because that edge would silently widen every future customer route to staff.

Additive, and widening only. A service still on 2.0.0 behaves exactly as it did — SUPER_ADMIN simply stays locked out there — so this needs no coordinated deploy. Since every service declares ^2.0.0 but installs from a lockfile, pick it up with:

npm i @easyweb/authentication@^2.1.0

The new effectiveRoles(roles) export does the same expansion for a service with its own guard (auth-service's DB-backed middleware, in particular).

The status is unchanged: authorize() still throws NotAuthorizedError, which is 401 even for a signed-in caller with the wrong role. Every service's http suite pins that. A caller needing to tell "not signed in" from "not permitted" must check the role itself.

Upgrading to 2.0.0 — BREAKING

The error classes moved to @easyweb/errors. Error handling is cross-cutting and has nothing to do with JWTs; a service needing ConflictError should not have to depend on an auth package for it.

- import { NotAuthorizedError } from "@easyweb/authentication";
+ import { NotAuthorizedError } from "@easyweb/errors";

@easyweb/errors is a peerDependency — install it alongside this package. Do not let it end up nested under node_modules/@easyweb/authentication/: two copies of CustomError means instanceof fails across the boundary and the error handler answers 500 for everything, with no type error to warn you. Verify with npm ls @easyweb/errors.

Also new in 2.0.0: extractToken and isValidAccessPayload are exported, for services that keep their own DB-backed middleware (see below) and would otherwise copy them.

Install

npm install @easyweb/authentication

express@^5 and jsonwebtoken@^9 are peer dependencies — the consuming service provides them.

Usage

Nothing in this package reads process.env. Config is bound once at startup, so the package never has to reach into a service's config module.

import express from "express";
import cookieParser from "cookie-parser";
import { createAuthMiddleware, requestContext } from "@easyweb/authentication";
import config from "./config";

const app = express();
app.use(cookieParser()); // required: the middleware reads the accessToken cookie
app.use(requestContext);

const authMiddleware = createAuthMiddleware(config.jwt);
// config.jwt must supply { secret, issuer, audience } matching auth-service's

app.get("/me", authMiddleware.authenticate, (req, res) => {
  res.json(req.user); // { id, email, username, roles, permissions }
});

app.get("/feed", authMiddleware.optionalAuth, (req, res) => {
  res.json({ personalised: Boolean(req.user) });
});

app.delete(
  "/admin/:id",
  authMiddleware.authenticate,
  authMiddleware.authorize(["admin"]),
  handler,
);

Minting tokens (auth-service only):

import { createJwtSigner } from "@easyweb/authentication";

const signAccessToken = createJwtSigner(config.jwt);
// config.jwt additionally needs accessTokenTtlSeconds

What it verifies — and what it does not

authenticate is stateless. It checks the signature, issuer, audience, expiry, and that the payload is a well-formed access token. It performs no database lookup.

A logout or session revoke in auth-service stays invisible here until the access token expires (JWT_ACCESS_TOKEN_TTL_SECONDS, currently 300). If a service needs immediate revocation, it must keep its own DB-backed middleware — auth-service does exactly that.

req.user.permissions is always []. The access token carries no permissions claim; auth-service resolves those from its own tables at request time. Guarding on this array would deny every request.

Exports

| Export | Purpose | |---|---| | createAuthMiddleware(config) | { authenticate, optionalAuth, authorize } | | requestContext | propagates / generates x-request-id | | createJwtVerifier(config) | (token) => JwtAccessPayload, throws on invalid | | createJwtSigner(config) | (claims) => string | | extractToken(req) | Bearer header, then the accessToken cookie | | isValidAccessPayload(decoded) | type guard: is this a well-formed access token? | | effectiveRoles(roles) | the roles held, expanded through the implication map (2.1.0) | | effectiveRoles(roles) | the roles held, expanded through the implication map (2.1.0) | | JwtAccessPayload, JwtAccessClaims, JwtVerifyConfig, JwtSignConfig | types |

extractToken and isValidAccessPayload exist for services that must keep a DB-backed middleware. They were previously private, so auth-service copied them — and the copies drifted. If you need the same checks with different error messages, import these rather than reimplementing them.

Importing the package also augments Express.Request with user, auth, and requestId. Remove any local copy of that declare global block or TypeScript will report duplicate members.

Token contract

JwtAccessPayload is the only shape the services agree on. Changing it breaks every consumer — bump the major version.

License

MIT