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

@m-kopa/platform-auth

v0.8.0

Published

Cloudflare Access JWT validation.

Readme

platform-auth

Cloudflare Access JWT validation.

Install

npm install platform-auth

Usage

import {
  createJwksCache,
  parseAccessJwtFromHeaders,
  verifyAccessJwt,
} from "platform-auth";

const jwks = createJwksCache(process.env.CF_ACCESS_JWKS_URL!);

const token = parseAccessJwtFromHeaders(request.headers);
if (token === null) return new Response("Unauthorized", { status: 401 });

const user = await verifyAccessJwt(token, {
  teamDomain: process.env.CF_ACCESS_TEAM_DOMAIN!,
  audience: process.env.CF_ACCESS_AUD!,
  jwks,
});

Gateway-fronted apps (confined origins)

If your app is fronted by the platform Entra-OIDC gateway and its pages.dev origin is confined (confine_origin=true), the apex bouncer strips Cf-Access-Jwt-Assertion. Read the gateway's un-clobbered X-Launchpad-User-Assertion instead, and verify against the gateway's issuer / audience / JWKS:

import { parseGatewayAssertionFromHeaders, verifyAccessJwt } from "platform-auth";

const token = parseGatewayAssertionFromHeaders(request.headers);
if (token === null) return new Response("Unauthorized", { status: 401 });

const user = await verifyAccessJwt(token, {
  teamDomain: process.env.GATEWAY_ISSUER!,
  audience: process.env.GATEWAY_AUD!,
  jwks: createJwksCache(process.env.GATEWAY_JWKS_URL!),
});

With the Hono middleware, pass header: "gateway" (default is "cf-access"):

createPlatformAuthMiddleware({
  header: "gateway",
  teamDomain: env.GATEWAY_ISSUER,
  audience: env.GATEWAY_AUD,
  jwks: createJwksCache(env.GATEWAY_JWKS_URL),
});

Each call reads exactly one explicitly-chosen header — there is no dual-read fallback.

Integration-lane requests (machine callers)

An approved integration calls your app through the gateway with an API key. The gateway checks the key, strips Authorization and Cookie, and forwards the request with a short-lived (5 minute) X-Launchpad-Integration-Assertion naming the integration. There is no user on these requests, so verify the assertion with verifyIntegrationAssertion, never with verifyAccessJwt or verifyJwt (both reject it).

import {
  createJwksCache,
  parseIntegrationAssertionFromHeaders,
  verifyIntegrationAssertion,
} from "@m-kopa/platform-auth";

const jwks = createJwksCache(env.GATEWAY_JWKS_URL);

const token = parseIntegrationAssertionFromHeaders(request.headers);
if (token === null) return new Response("Unauthorized", { status: 401 });

const { name } = await verifyIntegrationAssertion(token, {
  issuer: env.GATEWAY_ISSUER,
  host: env.GATEWAY_AUD, // your app's hostname, never the request URL
  method: request.method,
  path: new URL(request.url).pathname,
  jwks,
});
// `name` is the integration, e.g. "sales-backend". Authorise on it.

Take host from GATEWAY_AUD, not from the request URL. On v1 (Pages) origins the request your code sees is addressed to *.pages.dev, so a host read from the URL would never match, and trusting it would let the caller pick the audience. method and path do come from the request you are serving: that is what binds the assertion to this one endpoint.

If you have to verify the assertion without this package, check every one of these and fail closed on any miss:

  1. alg is RS256 and the signature verifies against the gateway JWKS (kid from the header).
  2. iss equals the gateway issuer.
  3. aud equals integration:<host>, with host from GATEWAY_AUD.
  4. exp is in the future and nbf is not in the future (small clock tolerance only).
  5. typ equals launchpad-integration.
  6. sub starts with integration: and the rest matches ^[a-z0-9][a-z0-9-]{0,62}$; that rest is the integration name.
  7. htm equals the request method, upper-cased.
  8. htu equals the request pathname exactly, with no normalisation (a trailing slash is a different path).

License

MIT