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

@sp-uvb/client

v0.1.0

Published

Universal Verification Broker (UVB) TypeScript/JavaScript SDK

Readme

@sp-uvb/client

Official TypeScript/JavaScript SDK for Universal Verification Broker (UVB).

Features:

  • Full TypeScript support with complete type definitions
  • Browser & Node.js compatible (ES modules + CommonJS)
  • Multiple storage options - Memory, localStorage, sessionStorage, cookies
  • Comprehensive error handling - Typed errors with detailed messages
  • Zero dependencies - Lightweight and fast
  • Tree-shakeable - Only bundle what you use
  • 100% test coverage - Reliable and production-ready

Installation

# npm
npm install @sp-uvb/client

# yarn
yarn add @sp-uvb/client

# pnpm
pnpm add @sp-uvb/client

Quick Start

Basic Usage

import { UvbClient } from '@sp-uvb/client';

// Create client
const client = new UvbClient({
  baseUrl: 'https://uvb.example.com',
});

// Start verification
const { transaction_id, challenges } = await client.startVerification(
  {
    user_id: 'user_123',
    tenant_id: 'tenant_a',
    email: '[email protected]',
  },
  {
    tenant_id: 'tenant_a',
    application_id: 'app_1',
    intent: 'login',
  }
);

// Continue with TOTP
const response = await client.continueVerification({
  transaction_id,
  challenge_id: challenges[0].challenge_id,
  factor_id: 'totp',
  response_payload: { otp: '123456' },
});

if (response.status === 'Succeeded' && response.assertion) {
  // Store JWT token
  await client.setToken(response.assertion);
  console.log('Authentication successful!');
}

With Token Storage

import { UvbClient, LocalStorageTokenStorage } from '@sp-uvb/client';

const client = new UvbClient({
  baseUrl: 'https://uvb.example.com',
  tokenStorage: new LocalStorageTokenStorage(),
});

// After successful authentication, token is automatically stored
// and persists across browser sessions

API Reference

UvbClient

Constructor

new UvbClient(config: UvbClientConfig)

Options:

  • baseUrl (required): Base URL of UVB API
  • timeout (optional): Request timeout in milliseconds (default: 30000)
  • headers (optional): Custom headers to include in all requests
  • fetch (optional): Custom fetch implementation
  • tokenStorage (optional): Token storage implementation (default: MemoryTokenStorage)

Example:

const client = new UvbClient({
  baseUrl: 'https://uvb.example.com',
  timeout: 10000,
  headers: {
    'X-Custom-Header': 'value',
  },
});

Methods

startVerification(subject, context)

Start a verification transaction.

const result = await client.startVerification(
  {
    user_id: 'user_123',
    tenant_id: 'tenant_a',
    email: '[email protected]',
  },
  {
    tenant_id: 'tenant_a',
    application_id: 'app_1',
    intent: 'login',
    ip_address: '192.168.1.1',
  }
);

console.log('Transaction ID:', result.transaction_id);
console.log('Available challenges:', result.challenges);
continueVerification(request)

Continue a verification with a factor response.

const result = await client.continueVerification({
  transaction_id: 'txn_123',
  challenge_id: 'chal_456',
  factor_id: 'totp',
  response_payload: { otp: '123456' },
});

if (result.status === 'Succeeded') {
  console.log('JWT token:', result.assertion);
}
enrollFactor(request)

Enroll a user in an authentication factor.

const result = await client.enrollFactor({
  subject: {
    user_id: 'user_123',
    tenant_id: 'tenant_a',
  },
  factor_id: 'totp',
});

console.log('TOTP secret:', result.enrollment_data.secret);
console.log('QR code:', result.enrollment_data.qr_code_url);
listEnrollments(request)

List all enrollments for a user.

const { enrollments } = await client.listEnrollments({
  user_id: 'user_123',
  tenant_id: 'tenant_a',
});

enrollments.forEach((enrollment) => {
  console.log('Factor:', enrollment.factor_id);
  console.log('Status:', enrollment.status);
});
deleteEnrollment(request)

Delete an enrollment.

await client.deleteEnrollment({
  enrollment_id: 'enr_123',
  user_id: 'user_123',
  tenant_id: 'tenant_a',
});
introspectToken(request)

Verify and extract claims from a JWT token.

const result = await client.introspectToken({ token: jwtToken });

if (result.active) {
  console.log('User:', result.sub);
  console.log('Factors:', result.factors_used);
  console.log('Assurance level:', result.assurance_level);
}
Token Management
// Store token
await client.setToken('eyJhbGc...');

// Get token
const token = await client.getToken();

// Remove token
await client.removeToken();

// Check if token exists
const hasToken = await client.hasToken();

// Verify current token
const claims = await client.verifyCurrentToken();
if (claims && claims.active) {
  console.log('Token is valid');
}

Token Storage

Available Storage Implementations

MemoryTokenStorage (Default)

Stores tokens in memory (not persistent).

import { MemoryTokenStorage } from '@sp-uvb/client';

const storage = new MemoryTokenStorage();

Use when:

  • Testing
  • Server-side applications
  • Single-page apps that don't need persistence

LocalStorageTokenStorage

Stores tokens in browser localStorage (persistent across sessions).

import { LocalStorageTokenStorage } from '@sp-uvb/client';

const storage = new LocalStorageTokenStorage('my_token_key');

Use when:

  • Browser apps needing persistence
  • Simple token storage requirements

Warning: Accessible by JavaScript, so only use for non-sensitive tokens.

SessionStorageTokenStorage

Stores tokens in browser sessionStorage (cleared when tab closes).

import { SessionStorageTokenStorage } from '@sp-uvb/client';

const storage = new SessionStorageTokenStorage();

Use when:

  • Browser apps
  • Tokens should not persist across sessions

CookieTokenStorage

Stores tokens in cookies.

import { CookieTokenStorage } from '@sp-uvb/client';

const storage = new CookieTokenStorage({
  cookieName: 'uvb_token',
  secure: true,
  sameSite: 'strict',
  maxAge: 3600,
});

Use when:

  • Need cookie-based authentication
  • Working with server-side rendering

Custom Storage

Implement your own storage:

import type { TokenStorage } from '@sp-uvb/client';

class CustomStorage implements TokenStorage {
  async setToken(token: string): Promise<void> {
    // Your implementation
  }

  async getToken(): Promise<string | null> {
    // Your implementation
  }

  async removeToken(): Promise<void> {
    // Your implementation
  }
}

const client = new UvbClient({
  baseUrl: 'https://uvb.example.com',
  tokenStorage: new CustomStorage(),
});

Error Handling

The SDK provides typed error classes for better error handling:

import {
  NetworkError,
  ApiError,
  RateLimitError,
  AuthenticationError,
  ValidationError,
} from '@sp-uvb/client';

try {
  await client.startVerification(subject, context);
} catch (error) {
  if (error instanceof RateLimitError) {
    console.log('Rate limited. Retry after:', error.retryAfter);
  } else if (error instanceof AuthenticationError) {
    console.log('Authentication failed');
  } else if (error instanceof NetworkError) {
    console.log('Network error:', error.message);
  } else if (error instanceof ApiError) {
    console.log('API error:', error.statusCode, error.errorCode);
  }
}

Error Types

  • UvbError - Base error class
  • NetworkError - Connection failures, timeouts
  • ApiError - HTTP errors (4xx, 5xx)
  • AuthenticationError - 401 errors
  • RateLimitError - 429 errors with retry-after
  • ValidationError - Invalid input
  • ConfigurationError - Invalid client configuration

Examples

Complete Authentication Flow

import { UvbClient, LocalStorageTokenStorage } from '@sp-uvb/client';

const client = new UvbClient({
  baseUrl: 'https://uvb.example.com',
  tokenStorage: new LocalStorageTokenStorage(),
});

async function login(userId: string, tenantId: string) {
  try {
    // 1. Start verification
    const { transaction_id, challenges } = await client.startVerification(
      { user_id: userId, tenant_id: tenantId },
      {
        tenant_id: tenantId,
        application_id: 'my_app',
        intent: 'login',
      }
    );

    // 2. Show available factors to user
    console.log(
      'Available factors:',
      challenges.map((c) => c.display_name)
    );

    // 3. User selects TOTP and enters code
    const otp = await promptUserForOTP(); // Your UI logic

    // 4. Continue verification
    const result = await client.continueVerification({
      transaction_id,
      challenge_id: challenges[0].challenge_id,
      factor_id: 'totp',
      response_payload: { otp },
    });

    // 5. Handle result
    if (result.status === 'Succeeded' && result.assertion) {
      await client.setToken(result.assertion);
      console.log('Login successful!');
      return true;
    } else {
      console.log('Login failed:', result.last_factor_result?.error_message);
      return false;
    }
  } catch (error) {
    console.error('Login error:', error);
    return false;
  }
}

TOTP Enrollment

async function enrollTOTP(userId: string, tenantId: string) {
  const { enrollment_data } = await client.enrollFactor({
    subject: { user_id: userId, tenant_id: tenantId },
    factor_id: 'totp',
  });

  // Display QR code to user
  showQRCode(enrollment_data.qr_code_url);

  // Or show secret for manual entry
  console.log('Secret:', enrollment_data.secret);

  return enrollment_data;
}

Protected API Requests

async function makeAuthenticatedRequest() {
  // Check if token is valid
  const claims = await client.verifyCurrentToken();

  if (!claims || !claims.active) {
    console.log('Not authenticated, redirecting to login...');
    return;
  }

  // Token is valid, proceed with request
  const token = await client.getToken();

  const response = await fetch('https://api.example.com/protected', {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });

  return response.json();
}

React Hook Example

import { useState, useEffect } from 'react';
import { UvbClient } from '@sp-uvb/client';

function useAuth(client: UvbClient) {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    checkAuth();
  }, []);

  const checkAuth = async () => {
    const claims = await client.verifyCurrentToken();
    setIsAuthenticated(claims?.active ?? false);
    setIsLoading(false);
  };

  const login = async (userId: string, tenantId: string, otp: string) => {
    // ... login logic
    await checkAuth();
  };

  const logout = async () => {
    await client.removeToken();
    setIsAuthenticated(false);
  };

  return { isAuthenticated, isLoading, login, logout };
}

TypeScript Support

The SDK is written in TypeScript and provides full type definitions:

import type {
  Subject,
  Context,
  Challenge,
  VerificationStatus,
  StartVerificationResponse,
  ContinueVerificationResponse,
  EnrollFactorRequest,
  IntrospectTokenResponse,
} from '@sp-uvb/client';

// All types are exported and fully documented

Browser Support

  • ✅ Chrome/Edge (latest)
  • ✅ Firefox (latest)
  • ✅ Safari (latest)
  • ✅ Node.js 16+

Contributing

Contributions are welcome! See CONTRIBUTING.md for details.


License

MIT License - see LICENSE for details.


Support