You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

@usewayn/server

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@usewayn/server

Server-side actions handler for Wayn PoW CAPTCHA.

0.0.2
latest
Source
npmnpm
Version published
Maintainers
1
Created
Source

@usewayn/server

A proof-of-work challenge system for rate limiting and bot protection. This SDK provides a server-side implementation for creating cryptographic challenges that clients must solve to prove computational work.

Installation

npm install @usewayn/server # NodeJS
bun install @usewayn/server # Bun

Quick Start

import Wayn from '@usewayn/server';

// Create a new Wayn instance
const wayn = new Wayn({
  stateless: true, // Optional: enables JWT authentication (default: true)
  jwtSecret: 'ReallySecretKey29!', // Optional: defaults to random bytes
});

// Create a challenge for the client
const challenge = wayn.createChallenge({
  challengeCount: 5,       // Number of challenges
  challengeSize: 32,       // Size of each challenge
  challengeDifficulty: 5,  // Difficulty level
  expiresMs: 300000,       // Expiration time (5 minutes)
});

// Validate a solution from the client
const result = await wayn.redeemChallenge({
  token: challenge.token,
  solutions: clientSolutions, // Array of [salt, target, nonce] tuples
});

if (result.success) {
  // Challenge solved successfully
  const validationResult = await wayn.validateToken(result.token);
  console.log('Token is valid:', validationResult.success);
}

API Reference

Constructor

new Wayn(config?: Partial<WaynConfig>)

Creates a new Wayn instance with optional configuration.

Parameters:

  • config.jwtSecret (string): Secret key for JWT token signing. Defaults to random bytes.
  • config.stateless (boolean): Whether to use JWT tokens (true) or in-memory tokens (false). Default: true.
  • config.state (ChallengeState): Initial state for challenges and tokens. Only used when stateless is false.

Methods

createChallenge(config?: ChallengeConfig)

Creates a new proof-of-work challenge for clients to solve.

Parameters:

  • config.challengeCount (number): Number of individual challenges. Default: 50
  • config.challengeSize (number): Size of each challenge string in characters. Default: 32
  • config.challengeDifficulty (number): Number of leading zeros required in hash. Default: 4
  • config.expiresMs (number): Challenge expiration time in milliseconds. Default: 600000 (10 minutes)
  • config.store (boolean): Whether to store the challenge server-side. Default: true

Returns:

{
  challenge: Array<[string, string]>, // Array of [salt, target] tuples
  token?: string,                     // Challenge token (if stored)
  expires: number                     // Expiration timestamp
}

Example:

const challenge = wayn.createChallenge({
  challengeCount: 5,
  challengeDifficulty: 3,
  expiresMs: 300000, // 5 minutes
});

// Send challenge.challenge to client
// Store challenge.token for validation

redeemChallenge(solution: Solution)

Validates a client's solution to a previously created challenge.

Parameters:

{
  token: string,                           // Challenge token
  solutions: Array<[string, string, number]> // Array of [salt, target, nonce] tuples
}

Returns:

{
  success: boolean,
  message?: string,  // Error message if success is false
  token?: string,    // Verification token if success is true
  expires?: number   // Token expiration timestamp
}

Example:

const result = await wayn.redeemChallenge({
  token: challengeToken,
  solutions: [
    ['salt1', 'target1', 12345],
    ['salt2', 'target2', 67890],
    // ... more solutions
  ]
});

if (result.success) {
  // Store result.token for future validations
  console.log('Challenge solved! Token expires at:', new Date(result.expires));
} else {
  console.error('Challenge failed:', result.message);
}

validateToken(token: string, config?: TokenConfig)

Validates a previously issued verification token.

Parameters:

  • token (string): The verification token to validate
  • config.keepToken (boolean): Whether to keep the token valid after validation (only for non-stateless mode). Default: false

Returns:

{
  success: boolean,
  payload?: JWTPayload  // JWT payload (only in stateless mode)
}

Example:

const validation = await wayn.validateToken(userToken);

if (validation.success) {
  if (validation.payload) {
    // Stateless mode - JWT token
    console.log('User ID:', validation.payload.id);
    console.log('Challenge solved at:', new Date(validation.payload.solvedAt * 1000));
    console.log('Average solution time:', validation.payload.avgSolutionTime, 'ms');
  }
  // Allow user to proceed
} else {
  // Token is invalid or expired
}

Configuration Options

Challenge Configuration

OptionTypeDefaultDescription
challengeCountnumber50Number of proof-of-work challenges to generate
challengeSizenumber32Length of each challenge salt in characters
challengeDifficultynumber4Number of leading zeros required in SHA-256 hash
expiresMsnumber600000Challenge expiration time in milliseconds (10 min)
storebooleantrueWhether to store challenge server-side for validation

Token Configuration

OptionTypeDefaultDescription
keepTokenbooleanfalseKeep token valid after validation (non-stateless only)

Usage Patterns

Rate Limiting

const wayn = new Wayn();

// Create challenge with higher difficulty for rate limiting
const challenge = wayn.createChallenge({
  challengeCount: 20,
  challengeDifficulty: 5, // Requires more computation
  expiresMs: 300000,      // 5 minutes
});

// Client must solve challenge before making API calls

Bot Protection

const wayn = new Wayn();

// Lighter challenge for bot protection
const challenge = wayn.createChallenge({
  challengeCount: 3,
  challengeDifficulty: 3,
  expiresMs: 120000, // 2 minutes
});

// Validate before allowing form submissions

Stateless vs Stateful Mode

Stateless Mode (Recommended):

  • Uses JWT tokens
  • No server-side storage required
  • Scales horizontally
  • Includes metadata about solution performance
const wayn = new Wayn({ stateless: true });

Stateful Mode:

  • Stores tokens in memory
  • Requires server-side state management
  • Better for single-instance deployments
const wayn = new Wayn({ stateless: false });

Security Considerations

  • JWT Secret: Use a strong, randomly generated secret for JWT signing in production
  • Challenge Difficulty: Higher difficulty provides better protection but increases client computation time
  • Expiration Times: Set appropriate expiration times based on your use case
  • Token Validation: Always validate tokens before allowing protected operations

TypeScript Support

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

import Wayn, { 
  WaynConfig, 
  ChallengeConfig, 
  Solution, 
  JWTPayload 
} from '@usewayn/server';

This project was created using bun init in bun v1.2.0. Bun is a fast all-in-one JavaScript runtime.

Keywords

security

FAQs

Package last updated on 28 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts