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

@lucid-dreams/agent-auth

v0.2.24

Published

Agent authentication runtime primitives

Readme

Agent Runtime Module Scaffold

Context & Goals

  • Build the @lucid-dreams/agent-auth runtime around the challenge → exchange → refresh loop while hiding protocol details from consumers.
  • Lean on the generated HTTP layer exported from packages/sdk/src/index.ts so every network call stays in sync with the server OpenAPI contract.
  • Deliver a structure that downstream teams can implement module-by-module without having to re-derive responsibilities.

Runtime Package Layout

src/
  runtime/
    agent-runtime.ts
    agent-auth-client.ts
    agent-api-client.ts
    token-manager.ts
    storage/
      memory-adapter.ts
      file-adapter.ts
      types.ts
    wallet/
      base-connector.ts
      coinbase-connector.ts
      privy-connector.ts
      local-key-connector.ts
    transport/
      http-transport.ts
      undici-transport.ts
      fetch-transport.ts
    events.ts
    errors.ts
    logger.ts
    config-loader.ts
  • The runtime owns orchestration and abstractions; all HTTP contracts flow through the generated SDK under @lucid-dreams/sdk.
  • CLI and agent-kit consumers import only the public surface inside src/runtime.

Generated SDK Integration

  • packages/sdk/src/index.ts re-exports sdk.gen (request builders) and types.gen (request/response types), so the runtime always imports from @lucid-dreams/sdk root.
  • The runtime currently relies on the following request builders:
    • Auth: postV1AuthAgentsByAgentRefChallenge, postV1AuthAgentsByAgentRefExchange, postV1AuthAgentsByAgentRefRefresh.
    • Agents: getV1Agents, getV1AgentsByAgentRef.
    • Wallet: postV1AgentsByAgentRefWalletSignMessage, postV1AgentsByAgentRefWalletSignTypedData, postV1AgentsByAgentRefWalletSignTransaction, postV1AgentsByAgentRefWalletSendTransaction.
  • See src/runtime/__tests__/sdk-contract.test.ts for a regression test that asserts these helpers remain available and keep their expected request shapes.
  • To regenerate the SDK after OpenAPI changes:
    1. pnpm --filter @lucid-dreams/sdk run openapi-ts
    2. pnpm --filter @lucid-dreams/sdk run build
    3. Re-run bun test (at minimum packages/agent-auth) to ensure the runtime still compiles.

Module Specifications

AgentRuntime (src/runtime/agent-runtime.ts)

  • Purpose: High-level façade that bootstraps config, authenticates on demand, and keeps tokens fresh.
  • Public Surface:
    • static fromConfig(options?: FromConfigOptions): Promise<AgentRuntime>
    • static load(options?: LoadOptions): Promise<AgentRuntimeLoadResult>
    • authenticate(): Promise<AuthenticatedSession>
    • ensureAccessToken(): Promise<string>
    • on(event: AgentAuthEvent, handler: EventHandler): () => void
    • shutdown(): Promise<void> (optional lifecycle hook to stop background refresh).
  • Collaborators:
    • ConfigLoader for config hydration.
    • AgentAuthClient for challenge/exchange/refresh.
    • AgentApiClient for authenticated API calls.
    • TokenManager for caching and refresh scheduling.
    • Logger + events.ts for observability.
  • Generated SDK Touchpoints: Delegates to AgentAuthClient, which is the only module talking to @lucid-dreams/sdk/auth.
  • Implementation Notes:
    • Start background refresh on first successful authenticate.
    • Emit Authenticated, TokenRefreshed, RefreshFailed, CredentialRevoked, ReauthenticationRequired events.
    • Provide escape hatches to override storage, transport, wallet connector, and logger via constructor options.
  • Status: Implemented AgentRuntime.fromConfig with configurable transport/auth/token wiring, background refresh, and event hooks, plus AgentRuntime.load convenience wrapper that composes the config loader (src/runtime/agent-runtime.ts, src/runtime/__tests__/agent-runtime.test.ts).

AgentAuthClient (src/runtime/agent-auth-client.ts)

  • Purpose: Typed wrapper over /challenge, /exchange, /refresh endpoints.
  • Public Surface:
    • requestChallenge(payload: ChallengeRequest): Promise<ChallengeResponse>
    • exchange(payload: ExchangeRequest): Promise<ExchangeResponse>
    • refresh(payload: RefreshRequest): Promise<RefreshResponse>
  • Collaborators:
    • Accepts an HttpTransport instance for network execution.
    • Uses WalletConnector to sign challenge payloads (if runtime delegates signing here).
    • Returns typed data using interfaces from @lucid-dreams/sdk/types.
  • Generated SDK Touchpoints:
    • Calls auth.challenge, auth.exchange, auth.refresh exported from sdk.gen.
    • Re-exports relevant TypeScript types (ChallengePayload, etc.) so consumers do not import the generated files directly.
  • Implementation Notes:
    • Inject baseUrl, clientId, agentId, and telemetry metadata through constructor options.
    • Translate HTTP errors into discriminated union errors defined in errors.ts.

AgentApiClient (src/runtime/agent-api-client.ts)

  • Purpose: Authenticated convenience layer over protected agent APIs.
  • Public Surface (held behind typed namespaces):
    • listAgents(params?): Promise<AgentsListResponse>
    • sendTransaction(payload): Promise<SendTransactionResponse>
    • Additional generated calls as coverage grows.
  • Collaborators:
    • Consumes the generated SDK groups (agents.*, transactions.*, etc.).
    • Accepts a callback getAccessToken(): Promise<string> to attach bearer tokens lazily.
    • Uses shared HttpTransport for retries/telemetry.
  • Generated SDK Touchpoints:
    • Import relevant groups from @lucid-dreams/sdk rather than reimplementing fetch.
    • Provide thin wrappers that enrich errors/events before re-throwing.
  • Implementation Notes:
    • Surfacing coverage: optionally track which generated endpoints remain unwrapped.
    • Expose only stable APIs; experimental ones live under experimental/ namespace.
  • Status: Agent API client scaffolded with listAgents, getAgent, signMessage, and sendTransaction, leveraging the shared transport + access-token callback with unit coverage (src/runtime/agent-api-client.ts, src/runtime/__tests__/agent-api-client.test.ts).

TokenManager (src/runtime/token-manager.ts)

  • Purpose: Persist access + refresh tokens, schedule refresh, dedupe concurrent refresh requests.
  • Public Surface:
    • getCachedAccessToken(): CachedToken | null
    • setTokens(tokens: TokenBundle): void
    • scheduleRefresh(trigger: () => Promise<TokenBundle>): CancelHandle
    • withRefreshLock<T>(fn: () => Promise<T>): Promise<T> (single-flight helper).
  • Collaborators:
    • StorageAdapter for persistence.
    • Logger + events for refresh telemetry.
  • Implementation Notes:
    • Default refresh window: 30s prior to exp.
    • Detect nonce/jti changes to guard against replayed refresh handles.
    • Provide serialization format for disk persistence and document it.

Storage Adapters (src/runtime/storage/*)

  • Purpose: Abstract persistence for refresh handles and metadata.
  • Interfaces:
    • StorageAdapter#get(key: string): Promise<StoredValue | null>
    • StorageAdapter#set(key: string, value: StoredValue): Promise<void>
    • StorageAdapter#clear(key: string): Promise<void>
  • Default Implementations:
    • MemoryStorageAdapter — in-process map.
    • FileStorageAdapter — JSON file with advisory locking to survive restarts.
  • Extensibility: Document how to supply custom adapters (Redis, AWS Secrets Manager) via AgentRuntime.fromConfig options.

Wallet Connectors (src/runtime/wallet/*)

  • Purpose: Provide signing capabilities for different execution environments.
  • Interface (base-connector.ts):
    • Extends the runtime ChallengeSigner interface with metadata helpers (getWalletMetadata(), getAddress(), supportsCaip2()).
    • Offers shared utilities for challenge normalization, stable JSON stringification, payload encoding detection, and signature extraction.
  • Concrete Connectors:
    • ServerOrchestratorWalletConnector — delegates signing to the hosted server orchestrator via the agent wallet endpoints.
    • LocalEoaWalletConnector — wraps local EOA signers (Node or browser) and supports message + typed data flows.
    • CoinbaseManagedWalletConnector (stub) — placeholder for Coinbase managed wallet orchestration.
    • PrivyEip191Connector (stub) — placeholder for Privy managed wallet signing.
  • Generated SDK Touchpoints: Connectors interact with @lucid-dreams/sdk wallet endpoints when delegating signature requests.
  • Implementation Notes: Guardrails for CAIP-2 chain matching, payload normalization, and metadata propagation are covered by dedicated unit tests.

HttpTransport (src/runtime/transport/*)

  • Purpose: Normalise HTTP execution across runtimes.
  • Interface:
    • request<T>(options: HttpRequestOptions): Promise<HttpResponse<T>>
  • Default Implementations:
    • undici-transport.ts for Node/Bun.
    • fetch-transport.ts for browser/edge environments.
  • Status: Fetch-based transport implemented with timeout handling, JSON helpers, and a fetch-compatible façade (asFetch()); Undici factory reuses the fetch transport while allowing optional dispatcher injection.
  • Responsibilities:
    • Handle retries, backoff, timeout, and instrumentation hooks.
    • Provide hook for injecting headers (user agent, telemetry metadata).
  • Generated SDK Touchpoints: The generated SDK accepts a fetch implementation; we should pass our wrapped transport to ensure consistent behaviour.

Logger & Events (src/runtime/logger.ts, src/runtime/events.ts)

  • Logger: Accept Pino-compatible logger; default to lightweight structured logger with redacted secrets.
  • Events:
    • Define AgentAuthEvent enum and payload contracts.
    • Provide subscription helpers used by AgentRuntime.
    • Emit events from AgentAuthClient, TokenManager, and AgentApiClient as relevant.

Config Loader (src/runtime/config-loader.ts)

  • Purpose: Merge configuration sources for the runtime.
  • Responsibilities:
    • Load .lucid-agent.json generated by CLI.
    • Overlay environment variables (LUCID_AGENT_*).
    • Accept runtime overrides (custom transport, storage adapter, wallet connector, logger).
    • Validate schema using zod/types exported from @lucid-dreams/sdk where available.
  • Status: Loader implemented with file/env/override precedence, sensible defaults, unit coverage, and now exposed through AgentRuntime.load for a one-call bootstrap that returns the resolved config and source metadata (src/runtime/config-loader.ts, src/runtime/agent-runtime.ts, src/runtime/__tests__/config-loader.test.ts, src/runtime/__tests__/agent-runtime.test.ts).

Errors (src/runtime/errors.ts)

  • Purpose: Centralised discriminated union for runtime failures.
  • Shape:
    • AgentRuntimeError union (CredentialRevoked, RefreshFailed, ChallengeFailed, TransportError, ConfigurationError, CoverageMismatch).
    • Include helper type guards (isCredentialRevoked(error) etc.).
    • Map generated SDK error responses into these unions.
  • Status: Client-facing error taxonomy extended for auth + agent API flows (AgentAuthClientError, AgentApiClientError, TokenManagerError) with contextual metadata surfaced to callers.

Cross-Cutting Concerns

  • Telemetry: Optional OpenTelemetry spans named agent.auth.challenge, agent.auth.exchange, agent.auth.refresh; attach HTTP status, retry count, latency.
  • Debug Mode: Toggle via LUCID_AGENT_DEBUG=1 to emit verbose logs without leaking tokens.
  • Edge Compatibility: Document required polyfills (crypto.subtle, TextEncoder) and how transports select runtime-specific implementations.
  • Testing:
    • Contract tests: mock generated SDK responses to verify token lifecycle scenarios.
    • Storage adapter tests: concurrency + persistence.
    • Integration smoke: run against local stack using the generated SDK to guarantee parity.
  • CLI Alignment: CLI should boot the runtime via AgentRuntime.fromConfig() and rely on AgentApiClient for admin operations.

Usage Examples

Quick start with createWallet

import { createWallet } from "@lucid-dreams/agent-auth";

const wallet = await createWallet({
  // Omitting `config` lets createWallet read standard LUCID_* environment variables
  events: {
    authenticated: (event) => {
      console.log("agent authenticated", event.accessToken);
    },
  },
});

await wallet.ensureAccessToken();

const signed = await wallet.signMessage({
  message: "gm",
});

console.log("signature", signed.signed);

await wallet.shutdown();

Integrate with viem

import {
  createWallet,
  createViemAccount,
} from "@lucid-dreams/agent-auth";
import {
  createPublicClient,
  createWalletClient,
  http,
  parseEther,
} from "viem";
import { base } from "viem/chains";

const lucidWallet = await createWallet();

// Ensure the wallet has an address (authenticate once if using the server orchestrator).
const account = await createViemAccount(lucidWallet, { chainId: base.id });

const publicClient = createPublicClient({
  chain: base,
  transport: http(),
});

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(),
});

const hash = await walletClient.sendTransaction({
  account,
  to: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  value: parseEther("0.01"),
});

console.log("submitted transaction", hash);

Want a runnable script? Check example/viem.ts for a full workflow that wires environment-driven configuration into a viem wallet client, signs messages, typed data, and demonstrates optional transaction signing.

Bootstrap with explicit config

import {
  AgentRuntime,
  MemoryStorageAdapter,
} from "@lucid-dreams/agent-auth";

const runtime = await AgentRuntime.fromConfig({
  config: {
    baseUrl: "https://lucid.daydream.systems",
    agentRef: process.env.LUCID_AGENT_REF!,
    credentialId: process.env.LUCID_AGENT_CREDENTIAL!,
    refreshToken: process.env.LUCID_AGENT_REFRESH_TOKEN,
    scopes: ["agents.read"],
  },
  wallet: {
    signer: myWalletConnector, // e.g. new ServerOrchestratorWalletConnector({...})
  },
  storage: new MemoryStorageAdapter(), // swap in a durable adapter in production
});

runtime.on("tokenRefreshed", (event) => {
  console.log("tokens rotated", event.expiresAt.toISOString());
});

const agents = await runtime.api.listAgents();
console.log("agent count", agents.items.length);

await runtime.shutdown();

Bootstrap from .lucid-agent.json

import { AgentRuntime } from "@lucid-dreams/agent-auth";

const { runtime, config, sourcePath } = await AgentRuntime.load({
  wallet: { signer: myWalletConnector },
  loader: {
    // optional overrides; defaults align with CLI output
    cwd: process.cwd(),
  },
});

console.log("loaded agent config from", sourcePath ?? "environment only");
console.log("authenticated agent ref", config.agentRef);

const session = await runtime.ensureAccessToken();
console.log("active scopes", session.scopes);

Use the server wallet connector

import {
  AgentRuntime,
  MemoryStorageAdapter,
  ServerOrchestratorWalletConnector,
} from "@lucid-dreams/agent-auth";

const serverWallet = new ServerOrchestratorWalletConnector({
  baseUrl:
    process.env.LUCID_SERVER_URL ??
    process.env.LUCID_BASE_URL ??
    "https://lucid.daydream.systems",
  agentRef: process.env.LUCID_AGENT_REF!,
});

if (process.env.LUCID_SERVER_ACCESS_TOKEN) {
  serverWallet.setAccessToken(process.env.LUCID_SERVER_ACCESS_TOKEN);
}

const runtime = await AgentRuntime.fromConfig({
  config: {
    baseUrl:
      process.env.LUCID_BASE_URL ?? "https://lucid.daydream.systems",
    agentRef: process.env.LUCID_AGENT_REF!,
    credentialId: process.env.LUCID_AGENT_CREDENTIAL!,
    refreshToken: process.env.LUCID_AGENT_REFRESH_TOKEN,
  },
  wallet: { signer: serverWallet },
  storage: new MemoryStorageAdapter(),
});

// Keep the orchestrator token in sync with runtime refresh events
runtime.on("authenticated", (event) => {
  serverWallet.setAccessToken(event.accessToken);
});
runtime.on("tokenRefreshed", (event) => {
  serverWallet.setAccessToken(event.accessToken);
});

Sign a transaction

const agentRef = process.env.LUCID_AGENT_REF ?? config.agentRef; // reuse the agent ref from your loaded config

const signed = await runtime.api.signTransaction(
  {
    caip2: "eip155:8453",
    params: {
      transaction: {
        to: "0x0000000000000000000000000000000000000000",
        value: "0x0",
        data: "0x",
      },
    },
    authorization_context: {
      reason: "lucid.example.sign-transaction",
    },
  },
  { agentRef }
);

console.log("signed transaction", signed.signed);

Customize transport and storage

import {
  AgentRuntime,
  createFetchTransport,
  MemoryStorageAdapter,
} from "@lucid-dreams/agent-auth";

const resolvedConfig = {
  baseUrl: "https://lucid.daydream.systems",
  agentRef: "agent-123",
  credentialId: "cred-123",
};

const runtime = await AgentRuntime.fromConfig({
  config: resolvedConfig,
  wallet: { signer: myWalletConnector },
  transport: createFetchTransport({
    baseUrl: resolvedConfig.baseUrl,
    fetch: myInstrumentedFetch,
    defaultHeaders: {
      "x-lucid-sdk-version": "agent-auth/0.1.0",
    },
  }),
  storage: new MemoryStorageAdapter(),
});

Implementation Checklist

  • [x] Implemented AgentAuthClient via generated SDK helpers with unit coverage (src/runtime/agent-auth-client.ts, src/runtime/__tests__/agent-auth-client.test.ts).
  • [x] Added AgentApiClient coverage for initial agent + wallet calls with unit tests (src/runtime/agent-api-client.ts, src/runtime/__tests__/agent-api-client.test.ts).
  • [ ] Finalise generated SDK namespace mappings (auth.*, agents.*, etc.) and document them here.
  • [ ] Create runtime module files with exported interfaces matching the above specs. (TokenManager + storage adapters + HTTP transport + AgentApiClient + AgentRuntime + ConfigLoader scaffolded with tests.)
  • [x] Implemented config loader with env/file/override precedence and tests (src/runtime/config-loader.ts, src/runtime/__tests__/config-loader.test.ts).
  • [x] Implement AgentRuntime bootstrap that wires ConfigLoader, TokenManager, AgentAuthClient, and AgentApiClient together.
  • [x] Added AgentRuntime.load convenience entrypoint that composes the config loader and surfaces resolved metadata (src/runtime/agent-runtime.ts, src/runtime/__tests__/agent-runtime.test.ts).
  • [ ] Provide default storage, transport, wallet connector, and logger implementations with the documented extension points.
  • [x] Add DX examples demonstrating how to call the runtime (const runtime = await AgentRuntime.fromConfig();).
  • [ ] Wire CI to regenerate SDK and run doc/example compilation to catch drift.