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

@okibi/partner-kit

v0.1.3

Published

Okibi Identity V1 verifier and partner integration kit

Readme

Okibi Partner Kit

@okibi/partner-kit is the maintained TypeScript/Node verifier for Okibi Identity V1. It verifies ES256 access-token JWTs and RFC 9449 DPoP locally, requires the configured issuer/audience and route scopes, then introspects an unseen jti.

Installation

bun add @okibi/partner-kit

The package is ESM-only and requires Node.js 20 or newer.

Claim namespace migration

Version 0.1.3 reads capability claims from the owned https://okibi.ai/claims/ namespace and temporarily accepts the legacy https://okibi.dev/claims/ names. If a token carries both forms, their values must agree. Upgrade every verifier to 0.1.3 before Okibi stops emitting the legacy names; Partner Kit 0.1.0 through 0.1.2 cannot read capabilities that contain only the new namespace.

Agent-assisted integration

The npm package includes an implementation skill for coding agents. After installing the package, ask the agent:

Read and follow node_modules/@okibi/partner-kit/skills/implement-okibi-identity/SKILL.md to integrate Okibi Identity into this API.

The skill covers both a database-free Better Auth design for tenant-level APIs and a durable subject-link design for applications that need a local user or fresh membership checks on every request.

DPoP is optional and off by default. The recommended factory accepts a dpop setting and reports that setting in its signed resolver response, so Okibi knows whether to issue Bearer or proof-bound capabilities. A Bearer integration needs no replay store and accepts only unbound Authorization: Bearer <token> capabilities. A DPoP integration verifies proofs automatically, but must provide a durable shared replay store; the factory rejects dpop: true or dpop: "required" at runtime when that store is missing. For compatibility with integrations created before the dpop option existed, supplying a replayStore while omitting dpop infers dpop: true; new integrations should set their intended mode explicitly.

The lower-level PartnerKit.verify() understands both token shapes. It accepts proof-bound capabilities only when constructed with a replay store. The lower-level createAccountResolverHandler() defaults to reporting { dpop: false }; opt in explicitly only when the protected API really has a durable DPoP verifier.

The two shapes cannot be mixed: a bound capability presented as Bearer, or an unbound one presented as DPoP or carrying a proof, is rejected. That is what stops a stolen bound capability from shedding its proof. identity.installation.keyThumbprint is present only for bound capabilities. A dpop: true verifier intentionally continues accepting correctly presented, unbound Bearer capabilities during a rollout; the token's cnf claim, not a caller-selected header, determines whether proof is required. After that overlap has drained, dpop: "required" refuses every unbound Bearer capability. Audit events record authorizationScheme and keyThumbprint so that overlap is visible.

Positive active state is cached until the earliest of 60 seconds, token expiry, or the introspection response expiry. A warm entry survives an Identity outage only until that fixed deadline; unseen tokens and expired entries fail closed.

The kit exposes neutral Node middleware plus Express and Fastify adapters, deterministic account-resolver outcomes, verified human/installation context, self-reported actor context, and a secret-free audit adapter. When present, the signed https://okibi.ai/claims/run_id is preserved beside act.sub as self-reported actor metadata in verified context and audit events; neither field is authorization authority. Capabilities with neither field omit actor context entirely. If either field is present, https://okibi.ai/claims/actor_trust must be self_reported; the kit rejects missing or orphaned provenance labels.

Deployment verification

Mount the kit's secret-free manifest handler at /.well-known/okibi-identity. The Okibi dashboard and okibi identity verify use it to find the resolver and a bounded set of safe GET/HEAD routes that must reject anonymous requests. This catches missing middleware, bad issuer metadata, and wiring drift; it does not replace the service's account, role, or object-authorization tests.

const identityManifest = createIdentityVerificationHandler({
  schema_version: 1,
  service_id: "projects",
  audience: "https://api.projects.example",
  issuer: process.env.OKIBI_ISSUER!,
  resolver_url: "https://api.projects.example/api/v1/identity/account-resolution",
  partner_kit_version: "0.1.3",
  protected_resources: [
    { method: "GET", path: "/api/v1/projects", required_scopes: ["projects:read"] },
  ],
});

Recommended integration

Partners own two application seams:

  1. Mount one account-resolution handler so Identity can ask which local account and tenant the human may use.
  2. Call one authorization function (or framework middleware) before protected API handlers, then continue through the service's existing role and object authorization.

createOkibiPartner wires both seams to one maintained verifier:

import { createOkibiPartner } from "@okibi/partner-kit";

const okibi = createOkibiPartner({
  dpop: false,
  issuer: process.env.OKIBI_ISSUER!,
  audience: process.env.OKIBI_AUDIENCE!,
  integrationId: process.env.OKIBI_PARTNER_INTEGRATION_ID!,
  integrationSecret: process.env.OKIBI_PARTNER_CLIENT_SECRET!,
  resolver: {
    integrationSecret: process.env.OKIBI_RESOLVER_CLIENT_SECRET!,
    supportedScopes: ["projects:read", "projects:write"],
    resolve: (input) => accounts.resolveOkibiIdentity(input),
  },
});

// POST /api/okibi/account-resolution
export const POST = okibi.accountResolver;

// Protected service route
return okibi.withIdentity(request, ["projects:write"], async (identity) => {
  const localLink = await accounts.findOkibiLink({
    issuer: identity.issuer,
    pairwiseSubject: identity.human.pairwiseSubject,
    tenantId: identity.tenant.id,
  });
  await permissions.requireProjectWrite(localLink, projectId);
  return Response.json(await projects.get(projectId));
});

The required V1 runtime values are issuer, audience, partner integration ID, partner integration secret, and a separate per-partner resolver secret. Identity's resolver caller ID defaults to okibi-identity. The introspection endpoint defaults to <issuer>/oauth/introspect; override it only for a nonstandard deployment. The two secrets are intentionally distinct: introspection authenticates the partner to Identity, while the resolver secret authenticates Identity to the partner and signs the partner's response.

For proof-of-possession hardening, set dpop: true and add replayStore: durableDpopReplayStore. DPoP replay state must be shared across production instances. createDevelopmentReplayStore() is available for tests and a single-process local server only.

Adopt strict DPoP in two phases. First deploy dpop: true and advertise DPoP, then wait at least the maximum capability lifetime plus clock skew so every previously issued unbound capability has expired. Finally change the verifier to dpop: "required". Switching directly from Bearer to strict mode would reject legitimate capabilities minted before the adoption completed.

Do not remove DPoP support in one deployment while Okibi can still mint bound capabilities. First stop advertising it while the DPoP verifier remains live: for resolver-derived support, deploy dpop: true with resolver.capabilities: { dpop: false } and complete an account-resolution; for explicitly registered support, update the partner registration to false (resolver reports intentionally cannot override it). Wait at least the maximum capability lifetime plus clock skew, then deploy with dpop: false and remove the replay store. This drains already-issued proof-bound capabilities instead of turning the downgrade into an outage.

withIdentity returns 401 invalid_token or 403 insufficient_scope with the correct Bearer/DPoP challenge for expected authorization failures. The scopes argument may be omitted when a route needs authentication but no additional scope. Errors thrown by the application handler, including the kit's exported error classes, are rethrown. The Node, Express, and Fastify adapters emit the same protocol responses; unexpected infrastructure errors go to Node/Express next(error) or are rethrown from the Fastify pre-handler.

The verified tenant claim is not a replacement for local authorization. Match issuer + pairwiseSubject + tenantId to the durable link created by the resolver, then apply the service's existing membership, role, and object rules.

Account resolver

createAccountResolverHandler is the lower-level resolver HTTP boundary used by createOkibiPartner. It accepts a Fetch Request, requires the partner-registered HTTP Basic credential (including RFC 6749 form-decoding), validates the frozen request fields and optional partner scope allowlist, then returns the validated outcome with the response authentication required by Identity Protocol v1:

const resolveAccount = createAccountResolverHandler({
  integrationId: "okibi-identity",
  integrationSecret: process.env.OKIBI_RESOLVER_INTEGRATION_SECRET!,
  supportedScopes: ["projects:read", "projects:write"],
  resolver: async (input) => {
    return await projects.resolveOkibiIdentity(input);
  },
});

export async function POST(request: Request) {
  return await resolveAccount(request);
}

Successful responses include x-okibi-resolver-timestamp and x-okibi-resolver-signature. The signature is base64url HMAC-SHA256(integrationSecret, timestamp + "." + exactResponseBody), prefixed with v1=. Identity rejects missing, expired, or invalid signatures. Partners must not stringify or modify the response body after the handler signs it.

OIDC relying party

OIDC is optional and separate from normal CLI delegation. Add it only when a resolver outcome needs the human to establish or resume a browser session at the partner. It is not required for the runtime capability middleware.

Simple application-owned login

When the application has no OIDC-capable auth stack, use createOkibiOIDCLogin. It owns discovery, high-entropy state, nonce and PKCE, issuer-bound callback validation, expiry, and single-use redemption. The application supplies durable transaction storage and turns the verified Okibi subject into its normal local account and session:

const okibiLogin = await createOkibiOIDCLogin({
  issuer: "https://identity.okibi.ai",
  clientId: process.env.OKIBI_OIDC_CLIENT_ID!,
  clientSecret: process.env.OKIBI_OIDC_CLIENT_SECRET!,
  redirectUri: "https://projects.example/auth/okibi/callback",
  transactions: durableOIDCTransactionStore,
});

const start = await okibiLogin.begin({ returnTo: "/projects" });
return Response.redirect(start.authorizationURL);

const result = await okibiLogin.callback(request.url);
await establishApplicationSession(result.identity);
return Response.redirect(result.returnTo ?? "/");

OIDCTransactionStore.consume must atomically remove the transaction. A single-process createDevelopmentOIDCTransactionStore is included for local development only.

Applications with a supported auth stack should run okibi identity federation init. The CLI detects installed providers, derives Better Auth and Auth.js callbacks, registers the relying party, stores the one-time credentials in a new 0600 file, and emits the exact provider configuration for those local libraries. Hosted providers require their provider-owned callback via --redirect-uri; the CLI emits their provider-specific configuration requirements.

discoverOIDCRelyingParty implements the cooperative partner connection ceremony without external runtime dependencies. Discovery fails closed unless the provider advertises Authorization Code, PKCE S256, pairwise subjects, ES256 ID tokens, every requested scope, and the configured token-endpoint authentication method. All discovered endpoints and the exact issuer must be valid HTTPS URLs in production. The local worktree profile may use an HTTP localhost, 127.0.0.1, or [::1] issuer; in that case every discovered endpoint must use the exact same loopback origin, including its port.

The caller owns the short-lived OIDC transaction. Generate high-entropy state, nonce, and a 43–128 character PKCE verifier, persist them in a server-side single-use record, and pass only the derived challenge to the authorization URL:

import { randomBytes } from "node:crypto";
import {
  discoverOIDCRelyingParty,
  pkceS256Challenge,
} from "@okibi/partner-kit";

const relyingParty = await discoverOIDCRelyingParty({
  issuer: "https://identity.okibi.ai",
  clientId: "projects-partner",
  clientSecret: process.env.OKIBI_OIDC_CLIENT_SECRET,
  redirectUri: "https://projects.example/oidc/callback",
  maxAuthenticationAgeSeconds: 300,
});

const transaction = {
  state: randomBytes(32).toString("base64url"),
  nonce: randomBytes(32).toString("base64url"),
  codeVerifier: randomBytes(32).toString("base64url"),
};
const redirectTo = relyingParty.authorizationURL({
  state: transaction.state,
  nonce: transaction.nonce,
  codeChallenge: pkceS256Challenge(transaction.codeVerifier),
});

On the callback, atomically consume that record and provide the received and expected state separately. exchangeCode validates state before contacting the token endpoint, sends the exact redirect URI and verifier, and verifies the returned ID token against the discovered JWKS:

const connection = await relyingParty.exchangeCode({
  code: callback.code,
  state: callback.state,
  expectedState: transaction.state,
  nonce: transaction.nonce,
  codeVerifier: transaction.codeVerifier,
});

Verification requires ES256, a unique matching public JWKS key, exact issuer, client audience and azp rules, nonce, valid exp/iat/auth_time, a pairwise sub, and—when the email scope is requested—a syntactically valid email with email_verified: true. An optional at_hash is checked when an access token is returned. The result omits the raw ID token and exposes its signature-verified claims, the normalized partner identity, and any returned access token. Omit clientSecret only for a registered public partner whose discovery metadata advertises token authentication method none.