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

@alternatefutures/ac-auth

v0.2.0

Published

Sign in with Alternate Clouds, framework-free: OpenID Connect discovery, PKCE, token exchange, single-flight refresh with rotation, a JWKS cache that survives issuer outages, session grace, typed claims and the device flow.

Readme

@alternatefutures/ac-auth

Sign in with Alternate Clouds, framework-free. Works in browsers, Node 20+ and edge runtimes. React components live in @alternatefutures/ac-auth-react, Next.js server helpers in @alternatefutures/ac-auth-next, and an Auth.js provider in @alternatefutures/ac-auth-js. This package is what they are built on, and what you use when none of them fits.

Install

npm install @alternatefutures/ac-auth

What you need first

An OAuth client, created under Organization › Developer in the Alternate Clouds web app: a public client for browser and native apps (PKCE, no secret) or a confidential one for servers. Register the exact redirect URI of your app; http://localhost:<port>/... is allowed for development.

Browser app in four calls

import { createAuthClient } from '@alternatefutures/ac-auth';

const auth = createAuthClient({
  clientId: 'ac_...',
  redirectUri: `${window.location.origin}/callback`,
  scope: ['openid', 'profile', 'email', 'wallet'],
});

// 1. Send the user to sign in (a button click).
await auth.signIn({ returnTo: '/dashboard' });

// 2. On /callback: finish the sign-in.
const { session, returnTo } = await auth.handleCallback();

// 3. Anywhere: the user, or a token for an API call. Refresh happens for you.
const user = await auth.getUser();
const token = await auth.getAccessToken();

// 4. Sign out.
await auth.signOut({ redirect: true });

session.user is typed:

| Field | Meaning | |---|---| | key | Store your local user under this. The wallet DID when the user has a verified wallet, otherwise the account id. | | id | The issuer subject (sub). | | name, email, emailVerified, picture | From the profile and email scopes. | | org | { id, slug, name, role } of the organization chosen at consent (org scope). | | wallet, wallets | did:pkh:eip155:1:<address> and every verified address (wallet scope). |

What the client guarantees

  • PKCE S256, state and nonce on every sign-in; the ID token is verified offline (EdDSA or ES256, issuer, audience, nonce, time).
  • Refresh rotation done safely. Every refresh returns a new refresh token and the old one dies; presenting an old one again revokes the whole grant. The client refreshes single-flight, hands the new tokens to late callers, and never sends a rotated token twice. A definitive invalid_grant means signed out; the client clears the session and tells subscribers.
  • Survives an issuer outage. Public keys are cached, served stale on error, and a snapshot embedded at build time is the last resort. When the issuer cannot be reached, an expired session stays usable in grace status for up to 24 hours, never more than 7 days after the tokens were issued (grace option; false disables it).
  • Discovery with a fallback. The issuer's discovery document is fetched and cached; if it cannot be fetched, the known endpoint layout is used.

Lower-level pieces

Everything the client does is exported on its own, for servers and custom flows:

import {
  discover, createPkcePair, buildAuthorizationUrl, parseAuthorizationResponse,
  exchangeAuthorizationCode, refreshTokenGrant, RefreshCoordinator,
  createJwksResolver, verifyIdToken, userFromClaims,
  evaluateGrace, startDeviceAuthorization, pollDeviceToken,
} from '@alternatefutures/ac-auth';

Device flow (CLIs, TVs)

Enable the device flow on the client, then:

const metadata = await discover('https://auth.alternatefutures.ai');
const device = await startDeviceAuthorization({ metadata, clientId, scope: 'openid email' });
console.log(`Open ${device.verification_uri_complete}`);
const tokens = await pollDeviceToken({ metadata, clientId, deviceCode: device.device_code, intervalSeconds: device.interval, expiresInSeconds: device.expires_in });

Errors

Every failure is an AuthError with a code; issuer refusals are an OAuthError with the RFC 6749 error string. Two helpers decide what to do: isSignedOutError(e) (clear the session, show the button) and isTransientError(e) (keep the session, try later).

Options worth knowing

| Option | Default | Notes | |---|---|---| | issuer | https://auth.alternatefutures.ai | Never changes; use the staging issuer for staging clients. | | scope | openid profile email | Add org (organization picker at consent) and wallet. | | sessionStorage | memory | session or local keep the session across reloads; any script on the origin can read them. Apps with a server should keep tokens server-side (@alternatefutures/ac-auth-next). | | clientAuthentication | { method: 'none' } | Confidential clients: client_secret_basic (the issuer default) or client_secret_post. Never in a browser. | | grace | 24 h / 7 d cap | false to expire with the access token. | | embeddedKeys | the build-time snapshot | Public keys trusted before the first JWKS fetch. |

License

MIT