paybito-slider-recaptcha
v1.0.0
Published
Drop-in slider CAPTCHA widget for Paybito's reCAPTCHA service. Pass the generate + solve API URLs and the widget handles the rest: render, drag, submit, refresh on failure, return a verification token.
Maintainers
Readme
Paybito Slider reCAPTCHA
A drop-in slider CAPTCHA widget for the Paybito reCAPTCHA service. Pass the generate and solve API URLs; the widget handles fetching the puzzle, rendering it, capturing the slider position, submitting the answer, refreshing on failure, and returning a verification token to your app.
UI is identical to paybito-slider-captcha — this package targets the newer two-call API (/v1/internal/generate + /v1/internal/solve) and returns a JWT token your backend forwards to /v1/siteverify.
Installation
npm install paybito-slider-recaptchaOr via CDN:
<script src="https://unpkg.com/paybito-slider-recaptcha@latest/index.js"></script>Quick start
import VerificationSlider from 'paybito-slider-recaptcha';
const captcha = new VerificationSlider({
generateApiUrl: 'https://recaptcha.paybito.com/v1/internal/generate',
solveApiUrl: 'https://recaptcha.paybito.com/v1/internal/solve',
sitekey: 'pbk_live_xxxxxxxx',
parentOrigin: 'https://your-app.com',
});
captcha.verify((result) => {
if (result.success) {
// result.token is the JWT — send it to your backend.
fetch('/api/login', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ email, password, captchaToken: result.token }),
});
} else {
console.log('Captcha failed or cancelled:', result.error);
}
});Configuration
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| generateApiUrl | string | yes | — | Full URL of the generate endpoint. |
| solveApiUrl | string | yes | — | Full URL of the solve endpoint. |
| sitekey | string | yes | — | Public site key (pbk_live_… / pbk_test_…). |
| parentOrigin | string | yes | — | Origin you claim to the server. Must be registered for the site via POST /v1/origins, otherwise the request is rejected with origin_not_allowed. |
| autoRefreshOnFail | boolean | no | true | Refresh the puzzle automatically after the user gets the position wrong. |
| maxAttempts | number | no | 3 | Give up after this many failed attempts and call back with { success: false, error: 'max_attempts' }. |
Callback contract
type VerificationResult =
| { success: true; token: string }
| { success: false; error: string };Success
{ success: true, token: 'eyJhbGc…' }Forward token to your backend, which calls /v1/siteverify with your site secret to redeem it. The token is single-use.
Failure error codes
| Code | Meaning | Recoverable? |
|---|---|---|
| cancelled | User closed the modal or pressed Escape. | Yes — let the user try again. |
| max_attempts | User used up all attempts. | Yes — surface a hint and let them try later. |
| network_error | Generate/solve POST failed at the transport layer. | Yes — show a retry button. |
| position_mismatch | Slider was outside the server's tolerance. | The widget already refreshed (if autoRefreshOnFail). |
| origin_not_allowed | The parentOrigin you passed isn't registered for this site. | No — fix your config. |
| invalid_sitekey | Bad/unknown sitekey. | No — fix your config. |
| channel_mismatch | The server detected the request channel (web vs. app) doesn't match the session. | No — fix your parentOrigin. |
| invalid_parent_origin | parentOrigin scheme isn't https://, http://, or app://. | No — fix your config. |
API
class VerificationSlider {
constructor(opts: VerificationSliderOptions);
init(): void; // mount modal into DOM
verify(cb: (r: VerificationResult) => void): void;
refreshCaptcha(): void; // drop current puzzle, fetch new
cancel(): void; // close + report cancelled
hideModal(): void; // alias for cancel()
destroy(): void; // remove DOM + CSS
}Using inside Electron (renderer)
If your Electron app's renderer is loaded via file:// or http://localhost:…, the renderer's actual origin is irrelevant to the server — what matters is the parentOrigin string you pass to this widget. Make sure it's registered:
POST https://recaptcha.paybito.com/v1/origins
Body: { "sitekey": "…", "secret": "…", "origins": ["https://your-app.com"] }Then in the renderer:
const captcha = new VerificationSlider({
generateApiUrl: 'https://recaptcha.paybito.com/v1/internal/generate',
solveApiUrl: 'https://recaptcha.paybito.com/v1/internal/solve',
sitekey: 'pbk_live_xxxxxxxx',
parentOrigin: 'https://your-app.com',
});If you'd rather route HTTP through the Electron main process (recommended for native-channel hardening with app://com.your.app), don't use this widget directly — see the integration guide for the IPC pattern.
Migrating from paybito-slider-captcha
The CSS classes and modal DOM are identical, so any custom styling carries over. Code changes:
| Old (paybito-slider-captcha) | New (paybito-slider-recaptcha) |
|---|---|
| new VerificationSlider({ apiEndpoint }) | new VerificationSlider({ generateApiUrl, solveApiUrl, sitekey, parentOrigin }) |
| result.gRecaptchaResponse (SHA256 hash) | result.token (JWT) |
| result.sessionId | (no longer surfaced — server holds session state) |
| tolerance option | (removed — server-side now) |
| imageWidth / imageHeight / pieceSize options | (removed — server tells the widget) |
| Client-side position validation | (moved to server) |
License
MIT — Md Athar [email protected]
