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

@humanity-org/connect-sdk

v0.2.1

Published

TypeScript SDK for the Humanity Public Dev API

Readme

npm License: MIT Node


What is Humanity Protocol?

Humanity Protocol provides decentralized, privacy-preserving identity verification. Users verify once and share proof of their attributes (like being human, being over 21, or being an accredited investor) without exposing personal data. This SDK makes it easy to integrate these verifications into your application.

Installation

npm install @humanity-org/connect-sdk

Quick Start

import { HumanitySDK } from '@humanity-org/connect-sdk';

// 1. Initialize the SDK
const sdk = new HumanitySDK({
  clientId: 'your-client-id',
  redirectUri: 'https://yourapp.com/callback',
  environment: 'production', // 'production' | 'staging' | 'testnet'
});

// 2. Generate security tokens and build the authorization URL
const state = HumanitySDK.generateState();
const nonce = HumanitySDK.generateNonce();

const { url, codeVerifier } = sdk.buildAuthUrl({
  scopes: ['isHuman', 'is21Plus'], // Request humanity proof + age verification
  state,
  nonce,
});

// 3. Redirect user to `url` and store `state`, `nonce`, and `codeVerifier` securely

// 4. After user approval, exchange the authorization code for tokens
const tokens = await sdk.exchangeCodeForToken({
  code: authorizationCodeFromCallback,
  codeVerifier: storedCodeVerifier,
});

// 5. Verify the state matches
if (!HumanitySDK.verifyState(storedState, stateFromCallback)) {
  throw new Error('Invalid state - possible CSRF attack');
}

// 6. Verify credentials
const result = await sdk.verifyPreset({
  preset: 'is21Plus',
  accessToken: tokens.accessToken,
});

console.log(result.value); // true if user is 21+
console.log(result.status); // 'active' | 'expired' | 'revoked'
console.log(result.expiresAt); // ISO timestamp when credential expires

Understanding Scopes vs Presets

Scopes

Scopes are OAuth 2.0 permissions that your application requests during the authorization flow. They determine what categories or specific fields of user data your app can access. Scopes are granted by the user during the consent flow.

  • Category scopes (e.g., identity:read, kyc:read) grant access to all low/medium sensitivity fields in that category
  • Field-level scopes (e.g., identity:date_of_birth) are required for high/critical sensitivity fields

Presets

Presets are pre-defined data fields you can retrieve once the user has granted the required scope. Each preset maps to exactly one scope - if the user grants that scope, you can access the preset.

Key Difference

  • Scopes = What you request permission for (during OAuth flow)
  • Presets = What data you retrieve (after authorization)

Available Scopes

| Scope | Category | Description | |-------|----------|-------------| | identity:read | Identity | Access to low/medium sensitivity identity fields | | identity:date_of_birth | Identity | Access to DOB and age-related fields (high sensitivity) | | identity:address_postal_code | Identity | Access to postal code (high sensitivity) | | identity:address_full | Identity | Access to full address (high sensitivity) | | identity:legal_name | Identity | Access to legal name (high sensitivity) | | kyc:read | KYC | Access to low/medium sensitivity KYC fields | | kyc:tax_residency | KYC | Access to tax residency (high sensitivity) | | kyc:tax_id | KYC | Access to tax ID/SSN (critical sensitivity) | | kyc:document_number | KYC | Access to document number (high sensitivity) | | financial:read | Financial | Access to low/medium sensitivity financial fields | | financial:net_worth | Financial | Access to net worth data (high sensitivity) | | financial:bank_balance | Financial | Access to bank balances (high sensitivity) | | financial:investment_balance | Financial | Access to investment balances (high sensitivity) | | financial:retirement_balance | Financial | Access to retirement balances (high sensitivity) | | financial:loan_balance | Financial | Access to loan balances (high sensitivity) | | financial:verified_income | Financial | Access to verified income (high sensitivity) | | profile.full | Profile | Access to full Humanity profile |


Available Presets

Identity Presets

| Preset Key | Required Scope | Type | Description | |------------|----------------|------|-------------| | is_human | identity:read | boolean | True if passed KYC or palm verification (1 person = 1 account) | | palm_verified | identity:read | boolean | User has completed palm biometric verification | | humanity_uuid | identity:read | string | Global UUID scoped to Humanity | | humanity_score | identity:read | number | Confidence score for "human + unique" status | | country_of_residence | identity:read | string | Country of residence (ISO 3166-1 alpha-2) | | residency_region | identity:read | string | Region bucket (e.g., EU/APAC) - derived from country_of_residence | | nationality | identity:read | string | Country of citizenship (ISO 3166-1 alpha-2) | | email | identity:read | string | Verified primary email | | phone | identity:read | string | Verified primary phone (E.164 format) | | social_accounts | identity:read | array | Verified social account identifiers/handles | | wallet_addresses | identity:read | array | List of user-controlled wallet addresses | | primary_wallet_address | identity:read | string | Selected primary wallet address | | age_over_18 | identity:date_of_birth | boolean | Whether user is ≥ 18 years old | | age_over_21 | identity:date_of_birth | boolean | Whether user is ≥ 21 years old | | age | identity:date_of_birth | integer | Age computed from date_of_birth | | date_of_birth | identity:date_of_birth | date | Full DOB (YYYY-MM-DD) | | legal_name | identity:legal_name | string | Full legal name from identity verification | | address_postal_code | identity:address_postal_code | string | Postal/ZIP code | | address_full | identity:address_full | string | Verified full address |

KYC Presets

| Preset Key | Required Scope | Type | Description | |------------|----------------|------|-------------| | kyc_passed | kyc:read | boolean | Overall KYC verification status | | kyc_level | kyc:read | enum | Level: none / basic / enhanced | | kyc_last_updated_at | kyc:read | datetime | Timestamp of last KYC verification update | | sanctions_clear | kyc:read | boolean | Sanctions list check result (e.g., OFAC) | | aml_screening_passed | kyc:read | boolean | AML screening result | | pep_status | kyc:read | boolean | Politically exposed person flag | | is_high_risk | kyc:read | boolean | High-risk customer indicator | | geo_blocked_region | kyc:read | boolean | User is in restricted geography | | employment_status | kyc:read | enum | Verified employment category | | document_type | kyc:read | string | Document type used for verification | | document_country | kyc:read | string | Issuing country of identity document | | document_expiry_date | kyc:read | date | Document expiration date | | tax_residency | kyc:tax_residency | string | Country of tax residency | | document_number | kyc:document_number | string | ID document number (sensitive) | | tax_id | kyc:tax_id | string | SSN / national tax ID (critical sensitivity) |

Financial Presets

| Preset Key | Required Scope | Type | Description | |------------|----------------|------|-------------| | cex_balance | financial:read | number | Centralized exchange balance | | trading_frequency_score | financial:read | number | Normalized trading activity score | | net_worth_above_10k | financial:net_worth | boolean | Verified net worth over $10,000 | | net_worth_above_100k | financial:net_worth | boolean | Verified net worth over $100,000 | | net_worth_total | financial:net_worth | number | Total assets − liabilities (USD) | | total_liabilities | financial:total_liabilities | number | Aggregated liabilities | | bank_balance_total | financial:bank_balance | number | Total bank account balances (USD) | | credit_card_balance | financial:credit_card_balance | number | Outstanding credit card balances (USD) | | loan_balance_total | financial:loan_balance | number | Outstanding loan balances (USD) | | investment_account_balance | financial:investment_balance | number | Investment account balances (USD) | | retirement_account_balance | financial:retirement_balance | number | Retirement/pension balances (USD) | | tradfi_balance | financial:tradfi_balance | number | TradFi net worth (bank/brokerage/retirement − liabilities) | | onchain_balance | financial:onchain_balance | number | On-chain balance | | verified_income | financial:verified_income | number | Income validated via employer/payroll (USD) |

Legacy Presets (Backward Compatibility)

| Preset Key | Required Scope | Type | Description | |------------|----------------|------|-------------| | humanity_user | profile.full | boolean | Humanity account basics: humanityId, email, wallet | | proof_of_assets | financial:net_worth | boolean | Verified assets via Mastercard Open Finance | | proof_of_investments | financial:investment_balance | boolean | Verified investment accounts via Mastercard | | proof_of_mortgage | financial:loan_balance | boolean | Verified mortgage via Mastercard | | proof_of_residency | identity:read | boolean | Verified residency via Mastercard bank data | | proof_of_retirement | financial:retirement_balance | boolean | Verified retirement savings via Mastercard |


API Reference

Configuration

const sdk = new HumanitySDK({
  // Required
  clientId: string;           // Your application's client ID
  redirectUri: string;        // OAuth callback URL

  // Optional
  clientSecret?: string;      // For server-to-server flows
  environment?: string;       // 'production' (default) | 'staging' | 'testnet'
  baseUrl?: string;           // Override API base URL
  defaultHeaders?: Record<string, string>;
  fetch?: typeof fetch;       // Custom fetch implementation
});

Troubleshooting Guide

| Error Code | Solution | |------------|----------| | E4003 | Include the required scope in the scope parameter during authorization | | E4004 | Record consent or verify the user - they haven't completed verification | | E4010 | User must re-verify - preset data expired after 24 hours | | E4041 | Refresh the access token using the refresh token | | E4042 | Re-authenticate the user - token was revoked or is invalid | | E4044 | Check the preset name - it doesn't exist in the available presets |

OAuth Flow

Build Authorization URL

const { url, codeVerifier } = sdk.buildAuthUrl({
  scopes: ['isHuman', 'is21Plus'], // Required: presets to request
  state: HumanitySDK.generateState(), // Recommended: CSRF protection
  nonce: HumanitySDK.generateNonce(), // Recommended: replay protection
  codeVerifier: customVerifier, // Optional: provide your own PKCE verifier
  codeVerifierLength: 64, // Optional: custom length (default: 64)
  additionalQueryParams: { // Optional: extra OAuth parameters
    prompt: 'consent',
  },
});

Exchange Authorization Code

const tokens = await sdk.exchangeCodeForToken({
  code: 'authorization_code_from_callback',
  codeVerifier: 'stored_code_verifier',
});

// tokens contains:
// - accessToken: string
// - refreshToken?: string
// - idToken?: string
// - expiresIn: number (seconds)
// - grantedScopes: string[]
// - presetKeys: string[] (e.g., ['isHuman', 'is21Plus'])
// - authorizationId: string
// - appScopedUserId: string

Refresh Access Token

const newTokens = await sdk.refreshAccessToken({
  refreshToken: tokens.refreshToken,
  scope: ['isHuman'], // Optional: request subset of original scopes
});

Revoke Tokens

// Revoke a single token
await sdk.revokeTokens({
  token: accessToken,
  tokenTypeHint: 'access_token',
});

// Revoke multiple tokens
await sdk.revokeTokens({
  tokens: [accessToken, refreshToken],
});

// Revoke an entire authorization (all tokens for a user)
await sdk.revokeTokens({
  authorizationId: tokens.authorizationId,
  cascade: true,
});

Credential Verification

Verify a Single Preset

const result = await sdk.verifyPreset({
  preset: 'isHuman',
  accessToken: tokens.accessToken,
});

console.log({
  value: result.value,       // boolean - true if credential is valid
  status: result.status,     // 'active' | 'expired' | 'revoked' | 'pending'
  expiresAt: result.expiresAt,
  verifiedAt: result.verifiedAt,
  evidence: result.evidence, // Additional verification metadata
});

Verify Multiple Presets (Batch)

const batch = await sdk.verifyPresets({
  presets: ['isHuman', 'is21Plus', 'isAccreditedInvestor'],
  accessToken: tokens.accessToken,
});

// Successful verifications
batch.results.forEach(result => {
  console.log(`${result.preset}: ${result.value}`);
});

// Failed verifications (e.g., user hasn't verified this credential)
batch.errors.forEach(error => {
  console.log(`${error.preset} failed: ${error.error.error_description}`);
});

Server-to-Server Token Issuance

For users who have already authorized your application, you can issue tokens without user interaction:

const result = await sdk.getClientUserToken({
  clientSecret: 'your-client-secret',

  // Identify the user (use one of these)
  email: '[email protected]',
  userId: 'user-id',
  evmAddress: '0x...',
  identifier: 'email|[email protected]', // Compound format
});

console.log(result.accessToken);
console.log(result.scopes); // Scopes from user's existing authorization

Polling for Updates

Track changes to user credentials and authorizations:

Credential Updates

const updates = await sdk.pollCredentialUpdates({
  accessToken: tokens.accessToken,
  updatedSince: '2024-01-01T00:00:00Z', // Optional: ISO timestamp or Date
  limit: 50, // Optional: max 100
});

updates.credentials.forEach(cred => {
  console.log(`${cred.preset}: ${cred.status} (expires ${cred.expiresAt})`);
});

console.log(updates.hasMore); // true if more results available
console.log(updates.lastModified); // Use as updatedSince for next poll

Authorization Updates

const updates = await sdk.pollAuthorizationUpdates({
  accessToken: tokens.accessToken,
  status: 'revoked', // Optional: filter by status
  updatedSince: new Date('2024-01-01'),
  limit: 50,
});

updates.authorizations.forEach(auth => {
  if (auth.status === 'revoked') {
    console.log(`Authorization ${auth.authorizationId} was revoked`);
  }
});

Discovery & Health

Get API Configuration

const config = await sdk.getConfiguration();

console.log(config.authorization_endpoint);
console.log(config.token_endpoint);
console.log(config.presets_available); // All available presets

// Clear cached configuration
sdk.clearCache();

// Force refresh
const freshConfig = await sdk.getConfiguration(true);

Health Checks

const liveness = await sdk.healthcheck();
console.log(liveness.status); // 'ok'

const readiness = await sdk.readiness();
console.log(readiness.status); // 'ok'
console.log(readiness.checks); // Detailed health checks

Error Handling

The SDK throws HumanityError for API errors with structured information:

import { HumanityError } from '@humanity-org/connect-sdk';

try {
  await sdk.verifyPreset({ preset: 'isHuman', accessToken });
} catch (error) {
  if (error instanceof HumanityError) {
    console.error({
      message: error.message,
      code: error.code,           // e.g., 'E4041', 'invalid_token'
      subcode: error.subcode,
      statusCode: error.statusCode, // HTTP status code
      context: error.context,     // Additional error context
    });

    // Handle specific errors
    if (error.code === 'E4041') {
      console.log('Preset not available for this user');
    }
  }
}

Common Error Codes

| Code | Description | |------|-------------| | E4003 | Forbidden - insufficient permissions | | E4004 | Invalid token or credentials | | E4010 | Unauthorized - token expired or invalid | | E4041 | Preset not found for user | | E4042 | Preset not available | | E4044 | Resource not found |

Rate Limiting

API responses include rate limit information:

const result = await sdk.verifyPreset({ preset: 'isHuman', accessToken });

if (result.rateLimit) {
  console.log({
    limit: result.rateLimit.limit,       // Requests allowed per window
    remaining: result.rateLimit.remaining, // Requests remaining
    reset: result.rateLimit.reset,       // Unix timestamp when limit resets
  });
}

TypeScript

This SDK is written in TypeScript and exports all types:

import {
  HumanitySDK,
  HumanitySdkConfig,
  TokenResult,
  PresetCheckResult,
  PresetBatchResult,
  CredentialUpdates,
  AuthorizationUpdates,
  HumanityError,
  RateLimitInfo,
  EnvironmentDescriptor,
} from '@humanity-org/connect-sdk';

Security Best Practices

  1. Store tokens securely - Never expose access tokens in client-side code or URLs
  2. Use state parameter - Always validate the state parameter to prevent CSRF attacks
  3. Use nonce for ID tokens - Validate the nonce in ID tokens to prevent replay attacks
  4. Store code verifier server-side - The PKCE code verifier should be stored in a server session, not client storage
  5. Handle token expiration - Check expiresIn and refresh tokens before they expire
  6. Keep client secrets safe - Never expose your client secret in client-side code

Example: Next.js Integration

// app/api/auth/humanity/route.ts
import { HumanitySDK } from '@humanity-org/connect-sdk';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';

const sdk = new HumanitySDK({
  clientId: process.env.HUMANITY_CLIENT_ID!,
  redirectUri: process.env.HUMANITY_REDIRECT_URI!,
});

export async function GET() {
  const state = HumanitySDK.generateState();
  const nonce = HumanitySDK.generateNonce();
  const { url, codeVerifier } = sdk.buildAuthUrl({
    scopes: ['isHuman'],
    state,
    nonce,
  });

  cookies().set('humanity_state', state, { httpOnly: true, secure: true });
  cookies().set('humanity_nonce', nonce, { httpOnly: true, secure: true });
  cookies().set('humanity_verifier', codeVerifier, { httpOnly: true, secure: true });

  redirect(url);
}

// app/api/auth/humanity/callback/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const code = searchParams.get('code');
  const state = searchParams.get('state');

  const cookieStore = cookies();
  const storedState = cookieStore.get('humanity_state')?.value;
  const codeVerifier = cookieStore.get('humanity_verifier')?.value;

  if (!HumanitySDK.verifyState(storedState!, state)) {
    return new Response('Invalid state', { status: 400 });
  }

  const tokens = await sdk.exchangeCodeForToken({
    code: code!,
    codeVerifier: codeVerifier!,
  });

  // Store tokens securely and redirect to app
  // ...
}

Support