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

@adep/auth-client

v0.1.1

Published

OIDC client SDK for AgentDeploy platform (exported apps and third-party apps)

Readme

@adep/auth-client — OIDC 接入 SDK

授权码 + PKCE 的客户端 SDK(任务单 AUTH-003),给导出子应用与第三方应用共用, 对应 PRD §2.16「登录即服务」的接入面:发现缓存、授权码 + PKCE、token 刷新与轮换、登出。 纯 HTTP 实现,框架无关(浏览器 / Vue / React / Node 服务端都能消费)。

⚠️ 现在还不能拿它接任何 adep 实例:平台侧的 OIDC 端点尚未注册成路由(见「平台侧现状」)。 本包也没有测试、没有仓内消费者、未发布到 npm。要接入请先读那一节。

安装

尚未发布到 npm,目前只能在 AgentDeploy 仓库内以 workspace 协议引用:

{ "dependencies": { "@adep/auth-client": "workspace:*" } }

发布准备缺 publishConfigfiles(缺哪几件见 docs/npm-publishing.md §1 与 §9)。

能力总览

  • 发现文档拉取与缓存GET ${issuer}/.well-known/openid-configuration,实例内缓存,TTL 默认 5 分钟; clearDiscoveryCache() 可手动失效。
  • 授权码 + PKCEcode_verifier 取 64 字节随机数的十六进制(128 字符),code_challenge 走 S256; state 取 32 字节(64 字符)并在换 token 前强制比对,不等即抛(防 CSRF)。
  • token 交换与刷新clientSecret 给了就走 client_secret_post(密钥进表单体,不走 Basic); 刷新遇 invalid_grant → 清空会话并抛错(配合服务端的 refresh token 一次性轮换语义)。
  • userinfo:带 Bearer <access_token> 拉取并回填到会话。
  • id_token 基础校验iss / aud / exp / iat 四项,不验签(见「已知风险」)。
  • 登出:清本地会话;仅当发现文档给了 end_session_endpoint 才返回 RP-Initiated Logout 跳转 URL。
  • 可注入 httpClientget/post 两方法的接口,便于测试替换与自定义 fetch。

用法

import { createAuthClient } from '@adep/auth-client'

const auth = createAuthClient({
  issuer: 'https://platform.example.com',
  clientId: 'app_xxx',
  redirectUri: 'https://myapp.example.com/callback',
  postLogoutRedirectUri: 'https://myapp.example.com/',
  // clientSecret 只在 Node 服务端构造时传;浏览器包里传等于公开
})

// 1) 跳登录:state / codeVerifier 要活到回调,本包不负责持久化
const { url, state, codeVerifier } = await auth.buildAuthorizeUrl()
sessionStorage.setItem('oidc', JSON.stringify({ state, codeVerifier }))
location.assign(url)

// 2) 回调:参数顺序是 (code, codeVerifier, 期望的 state, 实际回跳带的 state)
const { code, state: returned } = parseQuery(location.search) // parseQuery 由接入方自写,本包不导出
const saved = JSON.parse(sessionStorage.getItem('oidc')!)
const session = await auth.handleCallback(code, saved.codeVerifier, saved.state, returned)
console.log(session.accessToken)

// 3) 之后
const profile = await auth.fetchUserInfo()
const token = await auth.getValidAccessToken() // 过期则自动刷新
await auth.logout() // 返回 RP-Initiated Logout URL;发现文档没给该端点时返回 null

API

| 成员 | 行为 | 抛错 / 返回 | | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | getDiscovery() | 拉发现文档,TTL 内命中缓存 | 非 200 → Failed to fetch discovery document: HTTP <n> | | getJwks() | 按发现文档的 jwks_uri 取 JWKS | 非 200 → Failed to fetch JWKS: HTTP <n> | | buildAuthorizeUrl(params?) | 拼授权 URL(response_type=codecode_challenge_method=S256),返回 {url, state, codeVerifier} | params.extraParams 最后合并,可覆盖同名标准参数 | | handleCallback(code, codeVerifier, expectedState, actualState) | 校验 state → 换 token → 建会话,有 id_token 时从中解出 userInfo | state 不等 → State mismatch: possible CSRF attack;非 200 → Token exchange failed: <error> - <description> | | refreshToken() | 用会话里的 refresh token 换新会话(新 refresh 覆盖旧的) | 无 refresh token → No refresh token availableinvalid_grant → 清会话并抛 Refresh token invalid or already used (rotation semantics) | | getSession() / isAccessTokenExpired() | 读内存会话 | 未登录分别是 nulltrue | | getValidAccessToken() | 过期则先刷新再返回 | 无会话 → No active session | | fetchUserInfo() | GET userinfo_endpoint,回填 session.userInfo | 非 200 → Failed to fetch userinfo: HTTP <n> | | verifyIdToken(idToken) | 只校 iss/aud/exp/iat | 返回 {valid, payload, errors}不解签名 | | logout(options?) | 清会话;performRpInitiatedLogout 默认 true | 有 end_session_endpoint → 返回跳转 URL,否则 null | | clearDiscoveryCache() | 失效发现文档缓存 | — |

配置项:issuerclientIdclientSecret?redirectUripostLogoutRedirectUri?scopes?(默认 openid profile email)、discoveryCacheTtl?(默认 300000 ms)、httpClient?

运行环境

需要 fetchcrypto.getRandomValuescrypto.subtle.digestTextEncoderbtoa / atob

  • Node ≥ 19、Bun、浏览器安全上下文(HTTPS 或 localhost)都满足; 浏览器里非安全上下文没有 crypto.subtlebuildAuthorizeUrl() 会当场抛——这类"本地 http://192.168.x.x 调试登录"的坑与 SDK 无关,是运行环境限制。
  • 类型面是 lib: ES2022 + DOMtsconfig.json 里写明),不依赖任何 Bun 专有 API。

平台侧现状(读这一节再决定要不要接)

本包按发现文档去请求各端点,而这些端点在平台代码里的实际状态:

| 本包会请求的 | 平台侧实况 | | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | /.well-known/openid-configuration | 构造逻辑在 server/domains/authsvc/discovery.ts(含 handleDiscoveryRequest),未注册为路由server/api-app.tsauthsvc 零引用,且 server/domains/authsvc/ 没有 index.ts,插件 loader 扫不到它 | | /oauth/jwks | 同上,server/domains/authsvc/jwks.ts 有双钥轮转与 handleJwksRequest,调用方目前只有它自己的单测 | | /oauth/authorize/oauth/token/oauth/userinfo/oauth/revoke | 只有 discovery.ts 拼出来的字符串,没有实现;同意页(consent)在 server/ 下也搜不到 | | end_session_endpoint | 发现文档不输出该字段 → logout() 恒返回 null(本地清理仍生效) |

结论:拿本包连任何现有实例,第一步 getDiscovery() 就会 404。 接入应用注册面(server/domains/authsvc/clients/registry.ts:密钥哈希、回调白名单精确匹配、一次性明文密钥、 出境开关)只有服务类——它的存储端口 ClientRegistryStore 在仓内没有任何实现,控制台 UI 也不存在。

同批(completed 2026-09-03)三张任务单都标 status: done,实况分三条,每条都可现场复核:

  • AUTH-001(OIDC 端点组,touchesserver/api-app.ts / server/wiring.ts):discovery.tsjwks.ts 两个模块在,但没有任何一处把它们注册成路由——server/api-app.tsauthsvc 零引用, 且 server/domains/authsvc/ 没有 index.ts(17 个域目录里唯一一个),插件装载器扫不到它。
  • AUTH-002(接入应用注册表,touchesserver/db/schema/ 与两侧 drizzle/):两份 schema 与全部 迁移里都搜不到接入应用表,ClientRegistryStore 无实现,该文件也没有单测(0% 覆盖,即基线那 3 件红之一)。
  • AUTH-003(本包 + 导出子应用闭环,touchese2e/authsvc/):SDK 在,但 e2e/authsvc/ 目录不存在、 导出模板里没有 AUTH_* 登录接入段(server/domains/appexport/templates/ 只有一个 template-renderer.ts)。

这属 AGENTS.md §8 第 1 条(验收标准与现有行为冲突),需人类定:补接线单,还是回填三单的实况。

已知风险

  • verifyIdToken 不验签:它只解码 payload 校四项声明。getJwks() 取了 JWKS 但没有接进验签路径, 所以"验过了"不等于"签名可信"。需要验签的接入方要么自行用 JWKS 验(本包不内置加密库), 要么只把 id_token 当非安全提示——真正拿 userinfo 端点换资料才是可信路径。
  • 会话只存内存:不落 localStorage,刷新页面即丢(上面的 sessionStorage 那段是自己写的)。
  • 不排队并发刷新:多个 getValidAccessToken() 同时撞上过期会各发一次刷新, 配合服务端的一次性轮换,第二个请求会拿到 invalid_grant 并把会话清空。多标签页场景请自行加互斥。
  • 服务端不返 expires_in 时会话永不过期expiresAt = Date.now() + expires_in * 1000, 缺字段算出 NaNisAccessTokenExpired()NaN 返回 false → 不会触发刷新。
  • 只实现授权码 + 刷新两种 grant:没有 client_credentials、没有主动撤销(revoke)调用、没有动态注册。

脚本

  • pnpm --filter @adep/auth-client run typecheck:只编本包 src/**(2026-09-05 起有包级 tsconfig.json; 在那之前 tsc 向上命中仓库根配置——根配置 noEmit: true 且范围是全仓,脚本退出 0 但什么都没校验)。
  • pnpm --filter @adep/auth-client run build:产 dist/*.js + dist/*.d.ts当前不参与发布链路:仓库的发包构建走 scripts/build-package.ts,本包不在其支持清单内。
  • 本包没有测试。要补的话,优先补「发现文档缓存 TTL → 过期重取」「state 不等即抛」 「invalid_grant 清会话」三条——它们都用 httpClient 注入假响应即可,不需要真 IdP。