@north-light/identity

中文文档
0.3.573发布于 2026/11/02UNLICENSEDTypeScriptES Module

Northlight access-token verification and scope rules

原始使用文档
文档目录5 节
  1. Install
  2. Verify a token
  3. Parse and compare scopes
  4. Related
  5. License

@north-light/identity — verify directory-issued tokens and evaluate crouter scopes

crouter

npm

@north-light/identity is the token contract shared by crouter's runtime, @north-light/sdk and @north-light/plugin. It does two things: it verifies the signed JWTs that a Northlight directory issues (access tokens, ID tokens, outbound provider tokens and grant-sync notices) against the directory's published keys, and it parses and compares scope strings such as crtr:llm or crtr:memory:read:user:work/. It is ESM-only, depends only on jose, and has no side effects on import.

It is a verifier, not an identity provider. It never issues, signs or stores tokens, and it does not run a login flow; the directory does that. Most applications do not import it directly: the SDK's OAuth helpers and the plugin kit's auth option call it for you. Use it when you write your own provider or service that receives these tokens.

Docs · Plugin authentication · Apps with many users · crouter repository

Install

npm install @north-light/identity

Verify a token

Every verifier takes { token, jwks, issuer, audience } and returns the typed claims or throws. jwks is either a static JWKS object or a JwksCache.

import { JwksCache, verifyCallToken } from '@north-light/identity';

const issuer = 'https://directory.example.com';
const jwks = new JwksCache(issuer, fetch, `${issuer}/.well-known/jwks.json`);

export async function authorize(request: Request) {
  const token = request.headers.get('authorization')?.replace(/^Bearer /, '') ?? '';
  const verified = await verifyCallToken({
    token,
    jwks,
    issuer,
    audience: 'https://provider.example.com/crtr', // exactly the URL the provider registered
  });
  return (verified.scope ?? '').split(' '); // the provider's `<provider>:<group>` strings the caller holds
}

JwksCache keeps the last good key set for one issuer. When a token names a kid it has not seen, it refetches, at most once every 30 seconds, and concurrent requests share that fetch. A failed refresh leaves the previous keys in place. If you omit the third argument, it discovers jwks_uri from <issuer>/.well-known/openid-configuration.

FunctionChecksReturns
verifyCallTokentyp: at+jwt, ES256 or RS256 with a kid, signature, iss, aud (a string equal to audience), exp, iat; sub is user:<id>; client_id non-empty; scope a string when present; the act chain (at most 8 links; each sub a runtime:, app: or user: principal; grant and rev only on an app: link, and grant needs an integer rev ≥ 1, else MissingRevClaimError). A token with no act is refusedCallToken (sub, aud, chain presenter first, scope, and the verified claims)
verifyIdTokenES256, signature, iss, aud, exp; sub is user:<id>IdTokenClaims (email* when email was granted; name, given_name, family_name when profile was)
verifySyncNoticeES256 with a kid, purpose: grant_sync, lifetime of at most five minutes, 30 s clock toleranceSyncNoticeClaims (jti, iat, exp)

verifyCallToken is the one verifier for peer, app access, outbound provider and run-notice tokens; the older verifyAccessToken, verifyMachineToken and verifyOutboundToken are removed and tokens in their legacy shapes (no act) are refused. verifyCallToken authorizes nothing: the caller decides authority from the returned chain.

aud must match exactly; a trailing-slash difference is refused. The act claim of an outbound token is for audit only: nothing in this package authorizes on it.

Parse and compare scopes

import { parseScope, covers } from '@north-light/identity';

parseScope('crtr:files:rw:user:reports');            // returns the string, typed as Scope
parseScope('crtr:files:rw:user:../etc');             // throws TypeError: Unsupported scope

covers('crtr:memory:rw:user', 'crtr:memory:read:user:work'); // true: rw covers read, no path covers any path
covers('crtr:memory:read:user', 'crtr:memory:rw:user');      // false
covers('crtr:files:rw:user:.', 'crtr:files:read:user:a/b');  // true: `.` is the whole directory

The grammar parseScope accepts:

ScopeMeaning
crtr:llm, crtr:act, crtr:scheduleModel calls and starting runs; acting on nodes, files and bash; scheduling crons
crtr:memory:read:user[:path], crtr:memory:rw:user[:path], crtr:memory:manage:userThe person's documents, optionally limited to a path; manage covers both access levels
crtr:memory:read_private:userRead-only access to public and private documents; no path; covered by manage, covers only itself
crtr:memory:read|rw:app:<id>[:profile:<profile>[:path]]An app's documents
crtr:files:read|rw:user:<dir>, crtr:files:read|rw:app:<id>:<dir>, crtr:files:shareHost files a run may mount, and sharing them
crtr:conversations:read:app:<id>, crtr:objects:read:app:<id>Reading another app's conversations or node objects
crtr:peer:<id>A peer grant
<provider>:<group>A capability provider's own scope, such as the ones in an outbound token's scope

Paths are relative and refuse .., :, backslashes, whitespace and empty segments. A memory path ending in / covers that directory and everything below it; a file path names a directory and covers it and everything below, with . meaning the whole root. Passing grantee as the second argument to parseScope also refuses an app: holder other than the grantee. ENFORCED is the set of scopes crtr sys connect --scopes accepts when it mints a token. What each scope allows is in Scopes and trust.

  • @north-light/sdk: uses this package for ID-token verification and scope validation in its OAuth helpers.
  • @north-light/plugin: verifies the directory's outbound tokens for providers registered in the directory.
  • Main repository: the crtr CLI, the crtrd daemon,.

License

Proprietary. Copyright (c) 2026 Northlight Systems. All rights reserved. See LICENSE.

版本与发布记录

@north-light/identity 共发布 164 个版本,首次发布于 2026/10/10;过去 12 个月发布了 164 个版本。

版本发布日期距今
0.3.573latest2026/11/021 天前
0.3.5722026/11/021 天前
0.3.5712026/11/021 天前
0.3.5702026/11/021 天前
0.3.5692026/11/012 天前
0.3.5682026/11/012 天前

关于 @north-light/identity 的常见问题

@north-light/identity 是什么?

北极光访问令牌验证和范围规则

如何安装 @north-light/identity?

在项目目录运行 npm install @north-light/identity,或使用 pnpm add / yarn add / bun add。

@north-light/identity 支持 TypeScript 吗?

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

@north-light/identity 支持 ESM 还是 CommonJS?

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

@north-light/identity 可以商用吗?

@north-light/identity 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@north-light/identity 还在维护吗?

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