Skip to main content
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 call createChallenge() 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 when difficulty 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

Returns ChallengeToken[] — 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:
  1. Pass difficulty: "auto" directly to createChallenge() and let it call the selector internally.
  2. Call selectWorkload() yourself and pass the result via workload.
Both use the same engine, so the results match for equivalent inputs.
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.
Any calibration value coming from a browser request is untrusted. Ribaunt only uses it to raise work above the server-owned baseline, but you should still validate its shape before passing it through.

Validation

createChallenge() validates its inputs at runtime and throws if anything is invalid:
  • difficulty — must be a finite number and at least 1. Fractional values are rounded down with Math.floor().
  • amount — must be a finite number and at least 1. Fractional values are rounded down with Math.floor().
  • ttlSeconds — must be a finite number and at least 1. Fractional values are rounded down with Math.floor().
  • workload — if you provide it, the selected values must still fit the configured bounds.
Never let user-controlled request parameters flow directly into createChallenge() without validation.
Requires RIBAUNT_SECRET to be set as an environment variable. createChallenge() throws if the secret is missing or shorter than 32 UTF-8 bytes.