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

@happyvertical/auth

v0.111.6

Published

Unified authentication for Keycloak, Cognito, Nostr, and local ChatGPT sessions with OAuth2/OIDC and public key identity

Readme

@happyvertical/auth

Unified authentication interface supporting multiple providers.

Providers

  • Keycloak - Full OIDC/OAuth2 with admin capabilities
  • AWS Cognito - OAuth2 with hosted UI
  • Nostr - Decentralized public key identity

Installation

npm install @happyvertical/auth

Claude Code Context

Install Claude Code context files for AI-assisted development:

npx have-auth-context

This copies the package's AGENT.md documentation and metadata.json metadata to your project's .claude/ directory, enabling Claude to provide better assistance when working with this package.

Quick Start

import { getAuth } from '@happyvertical/auth';

// Keycloak
const auth = await getAuth({
  type: 'keycloak',
  serverUrl: 'https://auth.example.com',
  realm: 'my-realm',
  clientId: 'my-app'
});

// Cognito
const auth = await getAuth({
  type: 'cognito',
  region: 'us-east-1',
  userPoolId: 'us-east-1_xxx',
  clientId: 'xxx'
});

// Nostr
const auth = await getAuth({
  type: 'nostr',
  relays: ['wss://relay.damus.io']
});

// Authenticate
const result = await auth.authenticate({ username, password });
console.log(result.accessToken);

// Validate token
const claims = await auth.validateToken(token);

// Check role
if (await auth.hasRole(token, 'admin')) {
  // Admin access
}

Documentation

See AGENT.md for complete API documentation.

Authorization server

@happyvertical/auth/server provides a framework-independent OAuth 2.0 authorization-code issuer. It intentionally does not authenticate browser sessions or render consent: an application validates its current session and permissions, then calls parseAuthorizationRequest() and approve() with an application-owned OAuthConsentContext.

import { createAuthorizationServer } from '@happyvertical/auth/server';

const request = await server.parseAuthorizationRequest(url.searchParams);
const approved = await server.approve(request, {
  subject: session.userId,
  tenantId: session.activeTenantId,
});
return Response.redirect(approved.redirectUri, 302);

Supply a durable OAuthAuthorizationStorage implementation. Its consumeAuthorizationCode and rotateRefreshGrant operations must be atomic database transactions (or compare-and-swap operations); the exported in-memory store is for tests only. The server enforces S256 PKCE, exact redirect URI and resource binding, JWT signing/JWKS, refresh-token rotation with family replay revocation, and live authorization checks at both code exchange and refresh through OAuthIdentityProvider.revalidateConsent (the legacy refreshConsent hook is a fallback for both). Return the unchanged subject and tenant, optional replacement application claims, and optional scopes that are a subset of the grant. Return null to deny; changing identity, tenant, or expanding scope fails closed. Omitting claims removes previous application claims. JWT protocol claims are reserved. Consent supplied to approve may also narrow the requested scopes.

Stores must implement narrowRefreshGrant when refresh tokens are issued (the constructor rejects stores without it): atomically validate the replacement token hash and active grant, then persist only a subset of its current scopes. Throw on any failure. The server revokes the family on failed live checks or narrowing persistence; it never returns the replacement. Storage failures must reject; never return success before durable commit. A connection failure after commit can leave an unreachable hash-only grant, but must not expose any token. Concrete SQL adapters and dialect tests belong to the host application.

Path issuers such as https://host/oauth advertise endpoints under /oauth and RFC 8414 discovery at /.well-known/oauth-authorization-server/oauth. Public DCR accepts only code responses, authorization-code/refresh grants, allowed scopes, and HTTPS redirects. HTTP loopback redirects require explicit allowLoopbackRedirects: true for native/development clients. Resource servers must pass their own audience to verifyAccessToken(token, audience). Access-token verification requires typ: at+jwt, expiry, issued-at, subject, audience, token ID, client ID and scope with valid claim types. Registration bodies are limited to 16 KiB while streaming, including when Content-Length is absent or understated. Metadata permits at most 10 redirect URIs of 2,048 characters each, a 256-character client name, a 2,048-character scope string, two grant types and one response type. Direct register() calls apply the same field bounds. Oversized bodies return 413 before persistence; invalid metadata returns 400. Unknown extension metadata is ignored within the body limit. Revocation returns success for unknown or invalid tokens, but storage outages return a generic 500 server_error so callers can retry after recovery. CIMD is not implemented. The signing API supports one active key; overlapping signing-key rotation is not implemented. Hosts must supply a public JWK matching the private signing key and keep private material out of JWKS.

Local Sign in with ChatGPT

Node-only local applications can import @happyvertical/auth/local to manage their Sign in with ChatGPT session. The manager uses a 127.0.0.1 loopback callback, PKCE and OIDC validation, and writes account-scoped renewable credentials atomically with owner-only permissions. Pass a configuration path outside the project directory and open the returned authorization URL in the system browser. It never exposes credentials from sessions().

Use accessToken(clientId) before an authorized request; it serializes token refreshes. logout(clientId) always clears local credentials and reports whether remote revocation was confirmed. This local runtime does not make any inference request or use browser storage.

License

MIT

Refresh storage adapters must implement narrowRefreshGrant to atomically persist both the narrowed scopes and the current claims on the exact replacement token before it is returned. An explicit undefined claims value clears previous application claims. Token and revocation form bodies share the 16 KiB streaming limit with registration. Refresh requests may request a subset of the original grant scope; expansions are rejected.