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

@opsf/pct-core

v0.1.0

Published

Create, sign, and verify Privacy Claims Tokens (PCT) — reference implementation of the PCT specification v0.1

Readme

@opsf/pct-core

CI npm version

Node.js

Reference implementation of the Privacy Claims Token (PCT) Specification v0.1 — create, sign, verify, and audit cryptographically bound data-obligation tokens.

PCT is a portable, tamper-evident token that encodes data obligations (lawful basis, allowed purposes, jurisdiction rules, consent status, etc.) and travels with data through processing pipelines, enabling runtime compliance enforcement.

Features

  • Token creation & signing — RS256 (recommended) and HS256 algorithms
  • 8-check verification — signature, expiry, purpose, jurisdiction, consent, data category, transfer, extensions
  • Cryptographic data binding — SHA-2 hash of canonicalized data (RFC 8785) prevents token/data substitution
  • Tamper-evident audit records — every verification generates a hashable audit trail
  • Payload validation — check payloads against the PCT v0.1 schema before signing
  • Extension support — pluggable checks for x-{framework}:{field} claims (HIPAA, AI Act, DORA, etc.)
  • Zero runtime dependencies — uses the Web Crypto API (Node.js >= 18, browsers, edge runtimes)
  • Full TypeScript types — strict types for all PCT structures

Install

npm install @opsf/pct-core

Requires Node.js >= 18 (uses the Web Crypto API).

Quick start

import {
  createPCT,
  verifyPCT,
  generateRS256KeyPair,
  createAuditRecord,
} from "@opsf/pct-core";

// 1. Generate a signing key
const key = await generateRS256KeyPair("my-key-1");

// 2. Create a PCT bound to your data
const data = { patient_id: "P-123", readings: [1, 2, 3] };

const token = await createPCT(
  {
    valid_from: Math.floor(Date.now() / 1000),
    expires_at: Math.floor(Date.now() / 1000) + 86400 * 365,
    issuer: "https://example.com",
    subject_id: "dataset:patient-cohort",
    subject_type: "dataset",
    data_origin: "GB",
    data_categories: ["health"],
    lawful_basis: { bases: ["consent"], framework: "UK_GDPR" },
    allowed_purposes: ["clinical_analytics"],
    consent_status: true,
    consent_scope: ["clinical_analytics"],
    jurisdiction_rules: { permitted_regions: ["GB"] },
    hash_algorithm: "sha-256",
    hash_scope: "full_payload",
  },
  key,
  data, // automatically canonicalized, hashed, and bound
);

// 3. Verify the PCT
const result = await verifyPCT(
  {
    pct: token,
    requested_action: "process",
    requested_purpose: "clinical_analytics",
    processing_region: "GB",
    requestor_id: "analytics-service",
    request_timestamp: Math.floor(Date.now() / 1000),
    request_id: crypto.randomUUID(),
  },
  key,
  { data }, // verify data binding integrity
);

console.log(result.decision); // "ALLOW"

// 4. Generate a tamper-evident audit record
const audit = await createAuditRecord(request, result);
console.log(audit.record_hash); // 64-char hex SHA-256

See the examples/ directory for more detailed scenarios.

Architecture

┌─────────────┐    ┌──────────────┐    ┌──────────────┐
│  createPCT   │───>│  Compact PCT │───>│  verifyPCT   │
│  (sign.ts)   │    │  header.     │    │  (verify.ts) │
│              │    │  payload.    │    │              │
│  ┌─────────┐ │    │  signature   │    │  8-check     │
│  │ hashJSON│ │    └──────────────┘    │  procedure   │
│  │ (bind)  │ │                        │              │
│  └─────────┘ │                        │  ┌─────────┐ │
└─────────────┘                        │  │ audit   │ │
                                       │  │ record  │ │
                                       │  └─────────┘ │
                                       └──────────────┘

Module map

| Module | Purpose | Spec section | |---|---|---| | sign.ts | Token creation and signing | §5, §6 | | decode.ts | Parse compact tokens (no verification) | §5.1 | | verify.ts | 8-check verification procedure | §6 | | audit.ts | Tamper-evident audit records | §8 | | schema.ts | Payload validation against v0.1 schema | §5 | | keys.ts | Key generation, import, export | §5.2 | | hashing.ts | SHA-2 hashing with base64url output | §5.8 | | canonicalize.ts | JSON Canonicalization (RFC 8785) | §5.8 | | encoding.ts | Base64url encode/decode (RFC 4648) | §5.1 | | types.ts | All TypeScript type definitions | Full spec |

API reference

Token lifecycle

| Function | Description | |---|---| | createPCT(input, key, data?) | Create and sign a PCT. Auto-generates pct_id, issued_at, and data_hash. | | decodePCT(compact) | Decode a compact PCT string into { header, payload, signature } without verifying. | | verifyPCT(request, keys, options?) | Run the full 8-check verification. Returns { decision, checks, header, payload }. | | validatePayload(payload) | Validate a payload object against the PCT v0.1 schema constraints. |

Verification checks

verifyPCT performs the spec-mandated 8-check procedure in order:

| # | Check | Field(s) evaluated | Blocks when | |---|---|---|---| | 1 | Signature | header.alg, header.kid | Signature invalid or no matching key | | 2 | Expiry | valid_from, expires_at | Current time outside validity window | | 3 | Purpose | allowed_purposes | Requested purpose not listed | | 4 | Jurisdiction | jurisdiction_rules | Region not permitted or explicitly restricted | | 5 | Consent | consent_status, consent_scope | Consent required but missing or insufficient | | 6 | Data category | data_categories, lawful_basis | Special categories without adequate legal basis | | 7 | Transfer | transfer_restrictions | Destination not permitted or no mechanism | | 8 | Extensions | extensions | Any extension check fails |

A single failed check results in BLOCK. Pass data in options to also verify data binding integrity.

Verification options

const result = await verifyPCT(request, keys, {
  // Override current time for testing (seconds since epoch)
  now: 1743000000,

  // Verify data binding — recomputes hash and compares to data_hash
  data: originalPayload,

  // Custom extension checker for regulatory frameworks
  extensionChecker: (extensions, request) => [
    {
      check_name: "x-hipaa:covered_entity",
      result: extensions["x-hipaa:covered_entity"] ? "pass" : "fail",
      reason: "HIPAA covered entity verification",
    },
  ],
});

Key management

| Function | Description | |---|---| | generateRS256KeyPair(kid) | Generate an RSA-2048 key pair (recommended for multi-party). | | generateHS256Key(kid) | Generate an HMAC shared secret (single-organisation only). | | importRS256PublicKey(kid, jwk) | Import a public key from JWK for verification only. | | importHS256Key(kid, rawSecret) | Import a shared secret from raw ArrayBuffer. | | exportRS256KeyPair(keyPair) | Export key pair to JWK format for storage or distribution. |

Data hashing

| Function | Description | |---|---| | hashJSON(data, algorithm?) | Canonicalize (RFC 8785) and hash. Returns base64url. Default: sha-256. | | hashString(data, algorithm?) | Hash a UTF-8 string (CSV, XML, etc.). | | hashBytes(data, algorithm?) | Hash raw Uint8Array bytes. | | canonicalize(value) | JSON Canonicalization Scheme (RFC 8785). Sorted keys, no whitespace. |

Audit

| Function | Description | |---|---| | createAuditRecord(request, result) | Generate a tamper-evident audit record with SHA-256 record_hash. | | buildVerificationResponse(result, audit) | Build a spec-compliant verification response (§7.3). |

Schema validation

import { validatePayload } from "@opsf/pct-core";

const result = validatePayload(untrustedPayload);
if (!result.valid) {
  for (const err of result.errors) {
    console.error(`${err.field}: ${err.message}`);
  }
}

The full JSON Schema (Draft 2020-12) is also available at schema/pct-schema-0.1.json for use with standard validators like Ajv.

Supported algorithms

Signing

| Algorithm | Mechanism | Use case | |---|---|---| | RS256 | RSASSA-PKCS1-v1_5 + SHA-256 | Recommended. Multi-party / cross-organisation. | | HS256 | HMAC + SHA-256 | Single-organisation only. Must not cross org boundaries. |

Data hashing

| Algorithm | Status | |---|---| | sha-256 | Recommended | | sha-384 | Supported | | sha-512 | Supported | | MD5 | Prohibited (collision attacks) | | SHA-1 | Prohibited (collision attacks) |

Examples

The examples/ directory contains fully commented, runnable examples:

| Example | Description | |---|---| | 01-create-and-verify.ts | Complete token lifecycle: create, verify, audit | | 02-blocked-request.ts | Demonstrates all block scenarios (wrong purpose, region, key, tampered data) | | 03-ai-interaction.ts | AI model interaction with EU AI Act context and extensions | | 04-cross-border-transfer.ts | Cross-border data transfer with SCCs and adequacy decisions | | 05-schema-validation.ts | Payload validation against the PCT schema |

Run any example with:

npx tsx examples/01-create-and-verify.ts

Development

# Install dependencies
npm install

# Run tests (71 tests across 6 suites)
npm test

# Type-check
npm run lint

# Build
npm run build

# Format code
npm run format

See CONTRIBUTING.md for the full development guide.

Spec conformance

This library implements the PCT Specification v0.1 including:

  • Compact serialisation format (header.payload.signature, per RFC 7519 §7.2)
  • All required and conditional payload fields (§5)
  • RS256 and HS256 signing algorithms (§5.2)
  • Data binding via RFC 8785 canonicalization + SHA-2 hashing (§5.8)
  • The 8-step verification procedure (§6)
  • Enforcement API request/response contracts (§7)
  • Tamper-evident audit record generation (§8)
  • Payload validation against the v0.1 JSON Schema
  • Extension namespace support (x-{framework}:{field})
  • Conditional fields: consent_status/consent_scope, ai_context, transfer_restrictions

License

License TBD.