@powforge/ratelimit
v0.2.0
Published
Proof-of-work rate limiting middleware for Express/Fastify. No API keys, no third-party services. Clients prove computational work to access your API.
Maintainers
Readme
@powforge/ratelimit
Proof-of-work rate limiting for Express APIs. No API keys, no accounts, no third-party services.
Clients solve a SHA-256 puzzle to prove computational work before accessing your API. Solved proofs grant time-limited tokens for subsequent requests.
Install
npm install @powforge/ratelimitQuick Start
const express = require('express');
const { powRateLimit } = require('@powforge/ratelimit');
const app = express();
// Protect your API with PoW rate limiting
app.use('/api', powRateLimit({ difficulty: 14 }));
app.get('/api/data', (req, res) => {
res.json({ message: 'You proved computational work to get here' });
});
app.listen(3000);How It Works
- Client requests
/api/datawithout proof - Server responds
429with a SHA-256 challenge - Client finds nonce where
SHA256(salt + nonce)has N leading zero bits - Client retries with
X-PoW-Proof: salt:nonce:signatureheader - Server verifies and issues
X-PoW-Tokenfor subsequent requests (5 min TTL)
Client Integration
async function fetchWithPoW(url) {
let res = await fetch(url);
if (res.status === 429) {
const { challenge } = await res.json();
const nonce = await solveChallenge(challenge);
const proof = `${challenge.salt}:${nonce}:${challenge.signature}`;
res = await fetch(url, {
headers: { 'X-PoW-Proof': proof }
});
}
return res;
}
async function solveChallenge({ salt, difficulty }) {
for (let nonce = 0; ; nonce++) {
const hash = await sha256(salt + nonce);
const bits = parseInt(hash.substring(0, 8), 16);
if (bits < Math.pow(2, 32 - difficulty)) return nonce;
}
}Options
| Option | Default | Description |
|--------|---------|-------------|
| difficulty | 14 | Leading zero bits (14 = ~16k hashes, <1s) |
| tokenTTL | 300 | Token validity in seconds |
| challengeTTL | 120 | Challenge validity in seconds |
| secret | auto | HMAC signing secret |
| skipIf | null | (req) => boolean to bypass PoW |
Difficulty Guide
| Difficulty | Expected Hashes | Browser Time | Use Case | |-----------|----------------|-------------|----------| | 10 | 1,024 | ~25ms | Light protection | | 14 | 16,384 | ~350ms | Standard API protection | | 18 | 262,144 | ~12s | High-value endpoints | | 20 | 1,048,576 | ~23s | Rate-limit heavy consumers |
Data from empirical experiments on AMD EPYC 7443P. Browser times ~5x slower than server.
Why PoW Instead of API Keys?
- No accounts needed: Clients prove work, not identity
- No rate limit state: Server is stateless (tokens are self-contained HMACs)
- Bot deterrence: Automated scrapers must spend real CPU time per request
- Privacy-first: No tracking, no IP logging, no third-party calls
- Softwar thesis: Access costs energy, not credentials
Part of the PowForge Project
Built as part of the Softwar thesis research, testing proof-of-work as a universal access control mechanism.
- PoW CAPTCHA - Browser widget
- @powforge/ratelimit - API middleware
License
MIT
