createChallenge() is imported from ribaunt and called server-side to generate one or more proof-of-work challenge tokens. Each token is a signed JWT that the browser solver decodes and works against.
Import
Signature
difficulty accepts either a positive integer or the string "auto". In "auto" mode, Ribaunt picks a difficulty and amount at runtime using selectWorkload() based on an optional client calibration, a server-side riskScore, targetDurationMs, and the min/max bounds you configure. Calibration is treated as untrusted — a fast benchmark can only raise work up to your maximums, never lower the server-owned baseline.Parameters
You can callcreateChallenge() in either of two styles:
- positional arguments:
createChallenge(difficulty, amount, ttlSeconds) - an options object:
createChallenge({ difficulty, amount, ttlSeconds, context, workload })
number | "auto"
default:"5"
Number of leading zero hex digits required in the SHA-256 hash. Each increment roughly doubles solve time. Values above 6 may cause browsers to hang. Pass
"auto" to have Ribaunt select difficulty and amount adaptively — see Adaptive workload below.number
default:"4"
Number of challenge tokens to generate. More challenges increase total proof-of-work but also increase network bandwidth.
number
default:"30"
Challenge token lifetime in seconds. Tokens submitted after expiry are rejected by
verifySolution.string
Optional scope string that is bound into the challenge token. Supply the same value to
verifySolution({ context }) to require that the same context is used when verifying.Pick<Workload, 'difficulty' | 'amount'>
Optional shorthand for setting the challenge difficulty and amount together. Use this when you want to keep the challenge configuration in a single object.
Auto-hardness options
These fields are only used whendifficulty is "auto".
number
default:"750"
Desired browser solve time in milliseconds. The selector aims for this duration when it has calibration data.
number
default:"50"
Server-side risk appetite from 0–100. Higher scores bias the selector toward more work within your configured bounds, independent of the client calibration.
ClientCalibration
Untrusted client benchmark, typically forwarded from the widget when
challenge-method="POST" and calibrate="true" are set. Used as a raise-only signal: fast calibration can increase work up to your maximum bounds, a slow or fake one cannot reduce it below the server baseline.number
default:"3"
Lower bound for
difficulty when using "auto".number
default:"6"
Upper bound for
difficulty when using "auto".number
default:"1"
Lower bound for
amount when using "auto".number
default:"8"
Upper bound for
amount when using "auto".Return value
ReturnsChallengeToken[] — an array of signed JWT strings. Send this array to the browser as { challenges: tokens }.
Examples
Adaptive workload
Two paths are supported for adaptive difficulty:- Pass
difficulty: "auto"directly tocreateChallenge()and let it call the selector internally. - Call
selectWorkload()yourself and pass the result viaworkload.
selectWorkload() respects the configured bounds and returns a Workload object with difficulty, amount, and estimatedAttempts.
Calibration helpers
Ribaunt exposes calibration helpers for both environments so you can benchmark the runtime that will actually solve the challenge:calibrateClient is a cross-environment alias — bundlers resolve the correct implementation via the package export map.
Validation
createChallenge() validates its inputs at runtime and throws if anything is invalid:
difficulty— must be a finite number and at least1. Fractional values are rounded down withMath.floor().amount— must be a finite number and at least1. Fractional values are rounded down withMath.floor().ttlSeconds— must be a finite number and at least1. Fractional values are rounded down withMath.floor().workload— if you provide it, the selected values must still fit the configured bounds.
Requires
RIBAUNT_SECRET to be set as an environment variable. createChallenge() throws if the secret is missing or shorter than 32 UTF-8 bytes.