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

@btravstack/oauth-client

v0.48.1

Published

A TokenSource port for @btravstack/core: OAuth 2.0 client credentials and RFC 8693 token exchange, so a service calls another as itself or for a subject — cached per audience until shortly before expiry, one fetch shared by concurrent callers, and a stati

Readme

@btravstack/oauth-client

A TokenSource port for @btravstack/core: a bearer token so a service calls another as itself or for a subject, over client credentials or RFC 8693 token exchange — kept per audience until shortly before it expires, one fetch shared by concurrent callers, and a static adapter for tests.

📖 Documentation · API Reference

pnpm add @btravstack/oauth-client @btravstack/core @btravstack/config \
  @btravstack/di openid-client unthrown

Every dependency is a peer. Node >=22.12: openid-client is ESM-only, so the CommonJS build relies on require(esm).

A worked example

A port that needs a token for the inventory service, and the composition that provides one:

import {
  TokenSource,
  oauthClient,
  type TokenIssuerUnavailable,
  type TokenRefused,
} from "@btravstack/oauth-client";

class InventoryAuth extends Port("ReadmeInventoryAuth")<{
  readonly header: () => AsyncResult<string, TokenRefused | TokenIssuerUnavailable>;
}> {}

export const inventoryAuth = Provider(InventoryAuth)({
  inject: { tokens: TokenSource },
  sync: ({ tokens }) => ({
    header: () =>
      tokens
        .token({ audience: "https://inventory.internal", scope: "inventory:read" })
        .map(({ bearer }) => `Bearer ${bearer}`),
  }),
});

export const Gateway = Module("ReadmeGateway")({
  imports: [oauthClient()],
  provides: [inventoryAuth],
  exports: [InventoryAuth],
});

Putting the token on an oRPC client's Authorization header, without a Promise leaving the Result, is Call another service as itself.

Options

| Option | Where | What it is | | --------------------- | ------------------------------------- | --------------------------------------------------------------- | | OAUTH_ISSUER | environment, pinned by issuer | the authorization server — required | | OAUTH_CLIENT_ID | environment, pinned by clientId | this service's client — required | | OAUTH_CLIENT_SECRET | environment, pinned by clientSecret | its secret, from a Kubernetes Secret — required | | allowInsecureIssuer | oauthClient({ … }) | accept an http: issuer that is not loopback (default false) | | clock | oauthClient({ … }) | what a token's lifetime is measured against |

The full table — defaults, semantics and the reasoning — lives on the reference page, which is this list's one detailed home.

What it decides, and what it does not

It decides that discovery is lazy, so an issuer down at deploy fails the calls that need a token rather than the boot; that a token is reused until a minute before it expires, with fixed FIFO capacity so subject turnover stays bounded; that a refusal (TokenRefused, with the issuer's error code) and an outage (TokenIssuerUnavailable) are two typed errors; that every fetch is reported to Observers; and that an oauth-client health check follows the newest-started fetch per audience and scope, even when responses finish out of order. Each request is snapshotted at entry so caller mutation cannot change its grant or poison another credential's cache.

It does not decide what a failure means for your call — retrying belongs to your transport. On behalf of a subject, token({ audience, onBehalfOf: { token, tokenType, actor? } }) uses RFC 8693 exchange. The issuer must authorize delegation and mint the act claim; an actor credential is supplied when it requires one. The reasoning is in AGENTS.md.

License

MIT