Bot protection that
respects your users.
Replace "click all the traffic lights" with cryptographic proof. BioKyn is free, open source and self-hosted: no puzzles, no tracking, no third-party CAPTCHA, and no data leaving your infrastructure.
$ npm install @biokyn/server @biokyn/client- • Express and Next.js adapters
- • reCAPTCHA / Turnstile-compatible
/siteverify - • Redis-backed stores for multi-node deployments
- • Signed releases with npm provenance
How it works
Trust you can verify, not guess
Only evidence your server can check grants a token. Browser signals can raise suspicion, but they can never grant access.
Argon2id proof-of-work
A small, memory-hard computation runs in the visitor's browser and is bound to the request. It costs a person a moment and costs a bot farm real money at scale.
• Tunable difficulty
WebAuthn step-up
Returning visitors can use a passkey credential your server registered. Signature counters are checked, and credentials expire and can be revoked.
• Anonymous registration with PoW
Privacy-preserving tokens
Tokens are issued through an RFC 9497 VOPRF (ristretto255-SHA512), single-use, and replay-protected, with no cookies and no cross-site identifiers.
• Shared nullifier store
Motion signal demo
See how movement becomes a signal
Move your cursor or swipe in the box. The numbers below are computed live from your own movement in this page, with nothing sent anywhere. In BioKyn, motion is an advisory signal that can add friction; proof-of-work and WebAuthn are what grant tokens. This is an illustration, not a real token issuance.
Draw a curve
Developer experience
Up and running in minutes
import { BioKynVerifier, biokynExpress, generateServerSecrets,
createRateLimiter, MemoryRateLimitStore } from '@biokyn/server';
const verifier = new BioKynVerifier({
issuer: 'verify.example.com',
...generateServerSecrets(),
sites: [{ origin: 'https://example.com',
secret: process.env.BIOKYN_SITE_SECRET! }],
});
app.use(express.json());
app.use(biokynExpress(verifier, {
basePath: '/biokyn',
rateLimit: createRateLimiter({ store: new MemoryRateLimitStore() }),
}));import { requestInclusiveToken } from '@biokyn/client';
const { token } = await requestInclusiveToken({
basePath: '/biokyn',
expectedPublicKey, // pin your issuer key
});
// Send `token` to your backend, which calls
// POST /siteverify with { secret, response: token }Going to production? Read the deployment guide for shared Redis stores, key rotation and TLS.
Free forever. Open to everyone.
BioKyn is Apache-2.0 licensed. Try it, star it, file an issue, or send a pull request.