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

@msdongcha/auth-kit

v0.0.4

Published

Framework-agnostic authentication context, redirect, callback and session coordination utilities.

Readme

@msdongcha/auth-kit

发布

本机发布前先构建:在仓库根目录运行 pnpm --filter @msdongcha/auth-kit build,再进入 packages/auth-kit 运行 npm publish。

包配置不强制开启 provenance,因为本机无法自动生成该证明。从支持 provenance 的 CI 环境发布时,显式使用 npm publish --provenance,并按 npm 要求配置 OIDC 权限。

初始化

pnpm add @msdongcha/auth-kit

TokenStore 由业务应用实现。SDK 只通过它读取、轮换和清理 token;不会读取 React、Router、页面状态或浏览器存储。

import { create, type TokenStore } from '@msdongcha/auth-kit'

const tokenStore: TokenStore = {
  get: () => {
    const accessToken = sessionStorage.getItem('access_token')
    const refreshToken = sessionStorage.getItem('refresh_token')
    return accessToken ? { accessToken, refreshToken: refreshToken ?? undefined } : null
  },
  set: ({ accessToken, refreshToken }) => {
    sessionStorage.setItem('access_token', accessToken)
    if (refreshToken) sessionStorage.setItem('refresh_token', refreshToken)
    else sessionStorage.removeItem('refresh_token')
  },
  clear: () => {
    sessionStorage.removeItem('access_token')
    sessionStorage.removeItem('refresh_token')
  },
}

const auth = create({
  authDomain: 'https://iam.example.com',
  app: 'business-web',
  tokenStore,
})

authDomain 必须是 HTTPS;仅当 runtime 为 development 或 test 时允许 localhost HTTP。app 是认证入口使用的应用标识。fetchImpl 用于注入 fetch 实现或测试替身。

不要配置 allowedCallbackOrigins。回跳地址的白名单只由 IAM 服务端配置和校验,SDK 不在客户端复制这项授权决策。

create(config) 返回的客户端

validate()

校验认证域名及当前 runtime 是否允许该 URL。

const result = auth.validate()
if (!result.ok) console.error(result.error)

buildAuthorizeUrl(options?)

创建 IAM 登录地址,只输出 app、return_to 和可选的 state 参数。

const result = auth.buildAuthorizeUrl({
  returnTo: 'https://business.example.com/orders',
  state: 'csrf-state',
})

if (result.ok) window.location.assign(result.value)

显式传入 returnTo 时优先使用。浏览器中省略它时,SDK 使用当前页面的绝对 URL,并删除查询或 hash 中的 access_token、refresh_token、code、id_token 和 token 参数。非浏览器环境必须显式传入有效的 returnTo,否则返回 RETURN_TO_UNAVAILABLE。SDK 只校验 URL 格式与 runtime;最终回跳是否允许由 IAM 服务端决定。

appCode、clientId 和 callbackUrl 仍是迁移期的兼容别名,分别归一化为 app 和 returnTo;SDK 不会输出 client_id 或 callback_url。

login(username, password)

向 POST /api/v1/auth/token 发送 { username, password },将返回的 token 写入 TokenStore,并返回 token、可选的可信上下文和身份信息。

从 0.0.4 开始,调用方传入原始密码,SDK 在发送请求前将其按 UTF-8 → 标准 Base64(保留 = padding,非 Base64URL)编码为请求的 password 字段。不要在调用方预先编码;SDK 不会猜测密码是否已经编码,也不会裁剪空白或规范化原始密码。用户名保持原样。

例如 auth.login('alice', 'secret') 的请求体是 { "username": "alice", "password": "c2VjcmV0" }。后端必须先对 password 做 Base64 解码并按 UTF-8 还原,再校验原始密码;升级须与后端协议同步,仍接收原始密码的旧后端不兼容此版本。Base64 是编码,不是加密,生产环境仍须使用 HTTPS。此变更仅作用于 login(),不包含注册、重置密码或 SSO。

const result = await auth.login('alice', 'secret')
if (!result.ok) throw new Error(result.error)

refreshToken()

使用 TokenStore 中的 refresh token 调用 POST /api/v1/auth/refresh。同一客户端实例中的并发刷新会合并为一次请求;成功后轮换 token,失败时清空 token。

const result = await auth.refreshToken()
if (!result.ok) window.location.assign('/login')

getIdentity()

从 TokenStore 读取 access token,以 Bearer token 调用 GET /api/v1/auth/me,返回 IAM 远程响应中的 user、roles 和 permissions。SDK 不使用 JWKS,也不在本地解析 token。

const result = await auth.getIdentity()
if (result.ok && result.value.permissions.includes('orders:read')) {
  // 渲染订单入口
}

getContext()

同样通过 GET /api/v1/auth/me 获取远程数据,但只在响应包含可信的 principal_kind、selected_tenant、default_target 和 app_access 时返回 AuthContext。缺少这些字段时返回 AUTH_CONTEXT_MISSING;app_access.allowed 为 false 时返回 APP_ACCESS_DENIED。不会从 roles 或 memberships 推断上下文。

const result = await auth.getContext()
if (result.ok) console.log(result.value.selectedTenant)

getMemberships()

使用 TokenStore 中的 access token 调用 GET /api/v1/auth/memberships,返回 camelCase 的租户成员列表。SDK 会保留 membershipStatus;列表中的成员关系不代表服务端一定允许切换。

const result = await auth.getMemberships()
if (result.ok) {
  for (const membership of result.value) {
    console.log(membership.tenantId, membership.isDefault)
  }
}

switchTenant(membershipId)

使用当前 access token 调用 POST /api/v1/auth/switch-tenant。服务端返回完整的新 access token 和 refresh token 后,SDK 才会原子替换 TokenStore;请求失败或响应不完整时保留原会话。

同一客户端实例中,对相同 membership 的并发切换会合并为一次请求;切换未完成时请求其他 membership 会返回 TENANT_SWITCH_IN_PROGRESS。

const result = await auth.switchTenant('membership-id')
if (result.ok) {
  console.log(result.value.identity?.roles)
}

logout()

如果 TokenStore 中存在 refresh token,则调用 POST /api/v1/auth/logout 撤销它,请求体为 { refresh_token }。无论服务端请求成功或失败,SDK 都会清空本地 TokenStore;请求失败时返回 LOGOUT_FAILED。没有 refresh token 时只执行本地清理。

const result = await auth.logout()
if (!result.ok) console.error(result.error)

其他公开工具

sanitizeCallbackUrl(url)

返回已删除认证参数的路径、查询和 hash,适合回调页在写入 TokenStore 后清理浏览器地址。

window.history.replaceState(null, '', sanitizeCallbackUrl(window.location.href))

resolveTenantDecision(input)

优先消费 AuthContext 中受信任的 selected tenant。只有显式设置 allowLegacyDefault: true 时,才兼容一个激活的 legacy isDefault membership。

const decision = resolveTenantDecision({ context: authContext })
if (decision.ok) useTenant(decision.value.selectedTenant.id)

createAuthKit(config)

旧版兼容入口。它返回 validateConfiguration()、buildAuthorizeUrl()、decideDestination(context) 和 applySession(result, adapter?)。新业务使用 create();此入口仅保留给仍依赖旧配置和返回形状的调用方。

createRefreshCoordinator()

创建旧版 refresh single-flight 协调器。refresh(task) 会让同一实例中并发的布尔刷新任务共用一个 Promise。

const coordinator = createRefreshCoordinator()
await coordinator.refresh(() => refreshBusinessSession())

公开类型与结果

AuthKitConfig、AuthClient、TokenStore、TokenSet、AuthIdentity、AuthContext、TenantMembership、AuthKitResult、LoginResult、AuthorizeOptions、TenantDecision 和相关 legacy 类型均从包根导出。由 create() 返回的客户端方法返回 { ok: true, value } 或 { ok: false, error, retryable? };调用方应先判断 ok 再读取 value。

SDK 可以解包 IAM 的 { success, message, data } 响应信封,也兼容裸 JSON 响应。它不实现 IAM 后端授权、回跳白名单或 JWKS token 校验。