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

@agentkeychain/agent

v0.1.0

Published

Agent SDK for AgentKeychain — agent authentication and service token introspection.

Readme

@agentkeychain/agent

Agent SDK for AgentKeychain — agent identity and OAuth-style token issuance for AI agents.

This package contains two clients:

  • Agent — used by an agent. Holds a refresh token, mints short-lived access tokens, and drives the agent-side of an auth session (binding an agent identity to a service login).
  • ServiceClient — used by a service that consumes agent tokens. Wraps the RFC 7662 token introspection endpoint with HTTP Basic auth (client_id / client_secret).

Installation

npm install @agentkeychain/agent
# or
bun add @agentkeychain/agent

Agent

For agents that need to authenticate themselves to AgentKeychain and bind their identity to a service's auth session.

Setup

import { Agent } from "@agentkeychain/agent";

const agent = new Agent({
  agentId: process.env.AKC_AGENT_ID!,           // "agent_..."
  refreshToken: process.env.AKC_REFRESH_TOKEN!, // "art_..."
  authServerUrl: "https://agentkeychain.com",
  // Persist the new refresh token whenever it rotates:
  onTokenRotated: async (newToken) => {
    await saveSecret("AKC_REFRESH_TOKEN", newToken);
  },
});

Get a fresh access token

const accessToken = await agent.ensureAccessToken();

ensureAccessToken() returns a cached access token, refreshing it (and rotating the refresh token) if it's missing or within 30 seconds of expiry. Whenever the refresh token rotates, onTokenRotated is called so you can persist the new value — losing it means re-enrolling the agent.

Bind the agent to a pending auth session

When the agent navigates to a service's authorize URL and detects an <meta name="akc-session-id"> tag, it should call:

const result = await agent.authenticate(sessionId);
// { status: "authenticated", client_id, requires_consent }

Create a pre-bound auth session (CLI flow)

For flows where the agent generates the authorize URL on behalf of a user (e.g. a CLI handing a link to a human):

const { session_id, authorize_url, expires_in } = await agent.createSession(
  "https://example.com/oauth/authorize?client_id=...&..."
);

// Hand `authorize_url` to the user to complete consent.
// Then poll:
const status = await agent.checkSession(session_id);
// status.status: "pending" | "completed" | "expired"

Refresh a downstream client session

If your code is also acting as the OAuth client (holding a client_id / client_secret issued by AgentKeychain) and needs to refresh an end-user session:

const session = await agent.refreshClientSession({
  clientId: "akc_client_...",
  clientSecret: process.env.AKC_CLIENT_SECRET!,
  refreshToken: userRefreshToken,
  scope: "calendar.read",
});
// { accessToken, refreshToken, idToken, expiresIn, scope }

Errors

import { AgentError } from "@agentkeychain/agent";

try {
  await agent.ensureAccessToken();
} catch (err) {
  if (err instanceof AgentError) {
    switch (err.code) {
      case "REQUEST_FAILED":   // server returned an error response
      case "NETWORK_ERROR":    // couldn't reach the server
      case "TIMEOUT":          // request timed out
      case "INVALID_RESPONSE": // server returned non-JSON
    }
  }
}

Options

interface AgentOptions {
  agentId: string;
  refreshToken: string;
  authServerUrl: string;
  requestTimeout?: number;          // ms, default 10_000
  fetch?: typeof globalThis.fetch;  // override for testing
  onTokenRotated?: (newRefreshToken: string) => void | Promise<void>;
}

ServiceClient

For services that accept agent-issued tokens and need to verify them via the introspection endpoint.

Setup

import { ServiceClient } from "@agentkeychain/agent";

const service = new ServiceClient({
  endpoint: "https://agentkeychain.com",
  clientId: "akc_client_...",
  clientSecret: process.env.AKC_CLIENT_SECRET!,
});

Introspect a token

const result = await service.introspect(token);
// RFC 7662 response: { active, scope?, client_id?, sub?, exp?, ... }

if (!result.active) {
  return new Response("Unauthorized", { status: 401 });
}

Or just:

if (!(await service.isTokenActive(token))) { ... }

Errors

import { ServiceClientError } from "@agentkeychain/agent";

try {
  await service.introspect(token);
} catch (err) {
  if (err instanceof ServiceClientError) {
    switch (err.code) {
      case "AUTH_FAILED":      // invalid client_id / client_secret
      case "REQUEST_FAILED":   // server returned an error
      case "NETWORK_ERROR":    // couldn't reach the server
      case "TIMEOUT":          // request timed out
      case "INVALID_RESPONSE": // server returned non-JSON
    }
  }
}

Options

interface ServiceClientOptions {
  endpoint: string;
  clientId: string;
  clientSecret: string;
  requestTimeout?: number;          // ms, default 10_000
  fetch?: typeof globalThis.fetch;  // override for testing
}

License

Apache-2.0