@data-fair/lib-express

中文文档
2.0.0发布于 2026/10/29MITTypeScriptES Module近 30 天下载 1975

Middlewares and utility functions related to the use of Express in the data-fair stack.

原始使用文档
文档目录5 节
  1. Install
  2. Modules
  3. Session
  4. Scopes and bearer tokens
  5. Websockets and identities

@data-fair/lib-express

Express 5 middlewares and helpers shared by the web services of the data-fair stack: session reading, error handling, reverse-proxy aware request info, SPA serving, websocket server, identity webhooks.

Install

npm i @data-fair/lib-express @data-fair/lib-node express

Peer dependencies: @data-fair/lib-node@^3.0.0, express@5, and ws@8 (optional, only for ws-server.js).

Modules

Import pathDescription
@data-fair/lib-expressRe-exports the small common pieces: session.js, errorHandler, find utils, httpError, req-origin.js, site.js, serve-spa.js.
@data-fair/lib-express/session.jssession singleton: verifies the simple-directory session cookies, session.middleware() (also opens the request log context, see @data-fair/lib-node/log.js), reqSession() / reqSessionAuthenticated() / reqAdminMode() accessors.
@data-fair/lib-express/error-handler.jsExpress error handler: maps errors to status codes, logs 5xx as errors and 401/403 as warnings, hides 5xx details when NODE_ENV=production.
@data-fair/lib-express/req-origin.jsReverse-proxy aware request info: reqOrigin(), reqHost(), reqIp(), reqIsInternal(), assertReqInternalSecret(), secretKeyMatches()…
@data-fair/lib-express/site.jscreateSiteMiddleware(servicePathPart): extracts the site path prefix of the request, reqSitePath(), reqSiteUrl().
@data-fair/lib-express/serve-spa.jscreateSpaMiddleware(): serves a built SPA with UI config injection, cache headers and CSP.
@data-fair/lib-express/find-utils.jsmongoSort(), mongoPagination(), mongoProjection() from query parameters.
@data-fair/lib-express/req-perf.jsPer-route step durations in the df_req_step_seconds histogram.
@data-fair/lib-express/ws-server.jsWebsocket server with channel subscriptions, fed by @data-fair/lib-node/ws-emitter.js.
@data-fair/lib-express/identities/index.jscreateIdentitiesRouter(): receives the identity webhooks of simple-directory.
@data-fair/lib-express/async-handler.jsDeprecated: Express 5 handles async routes natively.

Session

The session reads the id_token cookies set by simple-directory and verifies them with its JWKS. Initialize it once with the URL of simple-directory, then apply the middleware:

import express from 'express'
import { session, reqSessionAuthenticated, errorHandler } from '@data-fair/lib-express'

session.init(config.privateDirectoryUrl)

const app = express()
app.use('/api', session.middleware()) // or { required: true }, { adminOnly: true }

app.get('/api/items', async (req, res) => {
  const { account, accountRole } = reqSessionAuthenticated(req) // 401 if not authenticated
  // ...
})

app.use(errorHandler)

Permissions, account roles, admin mode and the Vue side are covered by the data-fair-session skill.

Scopes and bearer tokens

  • Authorization: Bearer <token> is read before cookies, which are then never read. A token whose JWT header has typ: at+jwt is verified as an access token, and any failure is a 401. Any other bearer (empty, an API key, a session token, a token of another system) does not claim to be one: the request is anonymous.
  • A token with a scope claim produces sessionState.scopes (a non-string claim is a 401). A service that enforces scopes calls session.init(directoryUrl, lang, onlyDecode, { scopeAware: true }); otherwise every scope-restricted session gets a 403. scopeAware is also honoured by lib-node's SessionHandler (readStateFromCookie / readStateFromBearer), so consumers that use it directly are closed by default too.
  • An access token carries at most one organization membership (none = personal account); a token with several is refused with a 401.
  • requireScope('datasets:read') guards a route. It reads the session through session.reqWithScope(req, accepted) (cached on the request), so it needs no session.middleware(). assertReqScope(req, ...) is the synchronous variant for routes behind the middleware. hasScope / assertScope do the same in code. A session without scopes is unrestricted. A granted umbrella such as datasets already covers datasets:read, so it need not be listed. "Write implies read" is expressed by listing the accepted scopes, e.g. requireScope(['datasets:read', 'datasets:write']) (any one of them is enough). Build these lists with defineScopes of @data-fair/lib-common-types/scopes.js rather than by hand: it adds the umbrella and the global tier scopes (all:read, all:write, all:admin).
  • simple-directory signs scoped tokens and access tokens with a separate key set (/.well-known/scoped-jwks.json, key ids scoped-...). Older libs only know /.well-known/jwks.json and refuse those tokens, so a scoped token never acts with full role power on a service that was not upgraded. Access tokens split into cookies are refused, scoped tokens cannot carry superadmin claims and must expire, only RS256 is accepted.
  • In a scope-aware service every route that reads the session must check a scope first: requireScope(...) / assertReqScope(req, ...), or allowAnyScope / markScopeChecked(req) when any scope is fine (session machinery, public resources). Otherwise the session accessors (session.req(), reqSession() and friends) answer 403 to scoped sessions, also when only the raw user.scope claim is present. Unrestricted sessions are not concerned.
    • Mark scopes per route, with the narrowest scope the route needs.
    • Never apply allowAnyScope app-wide, outside the session machinery itself: it would open every route to every scope.
    • A mark lasts for the whole request: a route that checked a scope and calls next() into another handler passes the mark on to it.
  • Scoped operations are usable from browsers on other domains: mount session.bearerCors() before the routes of a scope-aware service. A call carrying Authorization: Bearer is answered from any origin (Access-Control-Allow-Origin: *, never with credentials) and its preflight is answered directly. A bearer token is not ambient, so the origin adds nothing to it: its scopes are what limit it. Calls without a bearer token get no CORS header. The middleware does nothing unless the session is scopeAware, so enforcing scopes and opening scoped operations to browsers go together.
  • Websockets (ws-server) refuse scoped sessions unless the service passes start(server, db, canSubscribe, { channelScopes }): channelScopes(channel) returns the scopes accepted on that channel (any of them), or undefined to refuse scoped sessions there (403). canSubscribe still applies afterwards. Scopes are checked per subscribe message, nothing is marked on the upgrade request.
  • session.reqForLogs(req) reads the session for logging only; never use it for authorization. It never throws and ignores the scope check requirement; 401/403 refusals are silent, other errors are reported as internal errors.
  • session.readState, readStateFromCookie and readStateFromBearer are raw readers: no route scope guard and no per-request cache. They are not meant for authorization.

Websockets and identities

版本与发布记录

@data-fair/lib-express 共发布 83 个版本,首次发布于 2024/10/08;过去 12 个月发布了 26 个版本。

版本发布日期距今
2.0.0latest2026/10/2916 天前
1.34.12026/10/2125 天前
1.34.02026/10/2025 天前
1.33.12026/10/2025 天前
1.33.02026/10/1926 天前
1.32.02026/10/1629 天前

关于 @data-fair/lib-express 的常见问题

@data-fair/lib-express 是什么?

Middlewares and utility functions related to the use of Express in the data-fair stack.

如何安装 @data-fair/lib-express?

在项目目录运行 npm install @data-fair/lib-express,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:express(5)、@data-fair/lib-node(^3.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@data-fair/lib-express 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@data-fair/lib-express 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@data-fair/lib-express 可以商用吗?

@data-fair/lib-express 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@data-fair/lib-express 的下载量有多少?

根据 npm 官方下载统计,@data-fair/lib-express 在 2026/10/12 – 2026/11/10 这 30 天内被下载 1,975 次,日均约 66 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@data-fair/lib-express 还在维护吗?

最新版本 2.0.0 发布于 2026/10/29(16 天前);至今共发布 83 个版本,其中过去 12 个月发布了 26 个;首次发布于 2024/10/08。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。