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

@dwk/indieauth

v0.1.0-beta.2

Published

IndieAuth authorization, token, and metadata endpoints with PKCE and DPoP-bound tokens.

Readme

@dwk/indieauth

IndieAuth authorization, token, and metadata endpoints with PKCE and DPoP-bound tokens.

Part of the @dwk IndieWeb + Solid cohort. See the package specification for the full requirements.

The identity layer rooted at the user's own domain. It runs the authorization-code + PKCE flow, issues DPoP-bound access tokens (bound via @dwk/dpop's cnf.jkt), and publishes an OAuth 2.0 / IndieAuth server-metadata document so clients can discover the endpoints and PKCE methods. The tokens it mints are consumed downstream by @dwk/micropub and validated by the Solid Pod Resource Server.

Endpoints

| Endpoint | Default path | Purpose | | ---------------------- | ------------------------------------------ | ---------------------------------------------------- | | Metadata | /.well-known/oauth-authorization-server | Discovery: issuer, endpoints, S256, DPoP algs. | | Authorization (GET) | /authorize | Validate request, authenticate/consent, issue code. | | Authorization (POST) | /authorize | Profile-URL exchange (identity only, no token). | | Token (POST) | /token | Redeem code → DPoP-bound access token. | | Revocation (POST) | /revocation | Revoke an issued token (RFC 7009). |

Every endpoint path is derived from baseUrl but can be overridden with an absolute URL, and routing matches on pathname — so the handler is mountable under any prefix.

Usage

import { createIndieAuth } from "@dwk/indieauth";

const indieauth = createIndieAuth({
  baseUrl: "https://example.com",
  scopesSupported: ["create", "update", "media"],
  // The library owns all protocol mechanics; you own authentication + consent.
  async approveAuthorization(req) {
    const user = await authenticateCurrentUser(req); // your concern
    if (!user) return new Response("login", { status: 401 }); // take over
    return { me: user.profileUrl, scopes: req.scopes, profile: user.profile };
  },
});

export default {
  fetch(request: Request, env: Env, ctx: ExecutionContext) {
    return indieauth(request, env, ctx);
  },
};

approveAuthorization returns either an approval ({ me, scopes?, profile? }) to mint a code and redirect, or a Response to take over the exchange (render a login/consent page, redirect to an external IdP, etc.).

Audience-restricted tokens (RFC 8707 / RFC 9700 §2.3)

When a client supplies one or more RFC 8707 resource parameters on the authorization (and, to narrow, the token) request, the issued token is audience-restricted: it carries an aud claim naming the resource server(s) it may be presented to, so a token leaked to one resource server cannot be replayed at another. Each requested resource must be a well-formed absolute URI and pass the optional resourceIndicatorPolicy (defaults to accepting any well-formed resource); an unacceptable value is rejected with invalid_target. Resource servers complete the restriction by passing their own identifier as the expected audience on verify (below).

Bindings

Declared as a TypeScript Env fragment; the handler fails loudly if either is missing:

  • AUTH_DB — a D1 database holding authorization codes and issued-token records. Authorization state is strongly consistent (never KV); single-use redemption is enforced with a conditional UPDATE ... RETURNING.
  • TOKEN_SIGNING_KEY — secret signing-key material for the HS256 access tokens.

Validating tokens (Resource Server)

import { verifyAccessToken } from "@dwk/indieauth";
import { verifyDpopProof } from "@dwk/dpop";

const result = await verifyAccessToken(token, env.TOKEN_SIGNING_KEY, {
  issuer: "https://example.com",
  // Optional: when set, the token MUST carry an `aud` (RFC 8707) including this
  // resource server's identifier, else it fails with `audience_mismatch`.
  audience: "https://media.example.com/",
});
if (result.valid) {
  const dpop = await verifyDpopProof({
    proof: request.headers.get("DPoP")!,
    htm: request.method,
    htu: request.url,
    accessToken: token,
    expectedJkt: result.claims.cnf.jkt, // completes the DPoP binding
  });
}

License

ISC