A dead simple CAPTCHA service utilizing ALTCHA's Proof of Work (PoW).
This was created for use in Pulsar.
- Secure HMAC-based challenge generation
- Fast verification with Proof of Work
- Simple REST API
- Type-safe with TypeScript
- Highly customizable configuration
- Built-in rate limiting
- Configurable logging
- CORS support
- Challenge expiration
- Site key and secret key pair support
Recommended: Just use our Docker image: ghcr.io/nexirift/riftcaptcha:latest, Docker Compose example here.
- Install dependencies:
pnpm install- Configure environment:
cp .env.example .env
# Edit .env with your configuration- Run development server:
pnpm devHealth check endpoint.
Response:
{
"status": "ok"
}Get current server configuration (sanitized).
Response:
{
"algorithm": "SHA-256",
"maxNumber": 100000,
"challengeExpiry": 300000,
"rateLimitEnabled": false
}Generate a new CAPTCHA challenge.
Response:
{
"algorithm": "SHA-256",
"challenge": "...",
"salt": "...",
"signature": "...",
"timestamp": "2026-01-04T12:00:00.000Z"
}Verify a CAPTCHA solution.
Request:
{
"payload": {
"algorithm": "SHA-256",
"challenge": "...",
"number": 12345,
"salt": "...",
"signature": "..."
}
}Response (Success):
{
"success": true,
"verified": true,
"timestamp": "2026-01-04T12:00:00.000Z"
}Response (Failure):
{
"success": false,
"verified": false
}| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 3000 |
NODE_ENV |
Environment mode (development, production, test) |
development |
| Variable | Description | Default |
|---|---|---|
HMAC_KEY |
Secret key for HMAC (minimum 32 characters) | Required |
| Variable | Description | Default |
|---|---|---|
MAX_NUMBER |
Maximum number for proof of work | 100000 |
SALT_LENGTH |
Length of the salt string | 12 |
ALGORITHM |
Hash algorithm (SHA-1, SHA-256, SHA-512) |
SHA-256 |
CHALLENGE_EXPIRY |
Challenge expiration time in milliseconds | 300000 (5 min) |
| Variable | Description | Default |
|---|---|---|
CORS_ENABLED |
Enable/disable CORS | true |
CORS_ORIGIN |
Allowed origins (comma-separated or *) |
* |
CORS_METHODS |
Allowed HTTP methods (comma-separated) | GET,POST,OPTIONS |
CORS_HEADERS |
Allowed headers (comma-separated) | Content-Type,Authorization |
| Variable | Description | Default |
|---|---|---|
RATE_LIMIT_ENABLED |
Enable/disable rate limiting | false |
RATE_LIMIT_WINDOW_MS |
Time window in milliseconds | 60000 (1 min) |
RATE_LIMIT_MAX_REQUESTS |
Maximum requests per window | 100 |
| Variable | Description | Default |
|---|---|---|
INCLUDE_TIMESTAMP |
Include timestamp in responses | true |
VERBOSE_ERRORS |
Include detailed error messages | false |
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL |
Logging level (none, error, warn, info, debug) |
info |
LOG_CHALLENGES |
Log challenge creation | false |
LOG_VERIFICATIONS |
Log verification attempts | false |
NODE_ENV=production
HMAC_KEY=your-very-secure-randomly-generated-key-here
MAX_NUMBER=250000
ALGORITHM=SHA-512
CHALLENGE_EXPIRY=180000
CORS_ENABLED=true
CORS_ORIGIN=https://yourdomain.com
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX_REQUESTS=50
VERBOSE_ERRORS=false
LOG_LEVEL=warnNODE_ENV=development
HMAC_KEY=development-key-at-least-32-chars-long
MAX_NUMBER=50000
ALGORITHM=SHA-256
VERBOSE_ERRORS=true
LOG_LEVEL=debug
LOG_CHALLENGES=true
LOG_VERIFICATIONS=trueMAX_NUMBER=500000
SALT_LENGTH=24
ALGORITHM=SHA-512
CHALLENGE_EXPIRY=120000
RATE_LIMIT_ENABLED=true
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=20
CORS_ORIGIN=https://yourdomain.com,https://app.yourdomain.comBuild and run:
pnpm build
pnpm start- Always use a strong, randomly generated HMAC key (minimum 32 characters)
- Configure CORS appropriately for production environments
- Keep your HMAC key secret and never commit it to version control
- Enable rate limiting in production to prevent abuse
- Use HTTPS in production
- Set
VERBOSE_ERRORS=falsein production - Use environment-specific
.envfiles - Regularly rotate your HMAC key
- Monitor logs for suspicious activity when
LOG_VERIFICATIONS=true
MAX_NUMBER=10000
ALGORITHM=SHA-1MAX_NUMBER=1000000
ALGORITHM=SHA-512
SALT_LENGTH=32MAX_NUMBER=100000
ALGORITHM=SHA-256
SALT_LENGTH=12