verify-hcaptcha
Version:
A fully typed library to verify hCaptcha.com tokens submitted by users when solving captcha challenges
83 lines (74 loc) • 3.28 kB
JavaScript
/**
A fully typed library to verify hCaptcha.com tokens submitted by users when solving captcha challenges.
@remarks
Note: this is an unofficial library; we are not affiliated with hCaptcha.com.
@example
Verify a token submitted by a user:
```typescript
import { verifyHcaptchaToken } from 'verify-hcaptcha';
const result = await verifyHcaptchaToken({
token: "USER-SUBMITTED-RESPONSE-TOKEN", // Required
secretKey: "YOUR-SECRET-KEY", // Required
siteKey: "YOUR-SITE-KEY", // Optional
remoteIp: "USER-IP-ADDRESS", // Optional
});
if (result.success) {
console.log("User is human");
} else {
console.log("User is robot");
}
```
@packageDocumentation
*/
import * as z from "zod/mini";
const rawHcaptchaResponseSchema = z.object({
success: z.boolean(),
challenge_ts: z.optional(z.string()),
hostname: z.optional(z.string()),
credit: z.optional(z.boolean()),
// See https://github.com/colinhacks/zod/discussions/4934 and https://github.com/colinhacks/zod/discussions/4939.
"error-codes": z.optional(z.array(z.string())),
score: z.optional(z.number()),
"score-reason": z.optional(z.array(z.string())),
});
const hCaptchaResponseSchema = z.pipe(rawHcaptchaResponseSchema, z.transform(({ success, hostname, credit, score, ...rest }) => ({
/** True if the token is valid and meets the specified security criteria (e.g., if the site key is associated to the secret key). */
success,
/** UTC timestamp of the challenge in ISO 8601 format (e.g., `2021-10-02T18:12:10.149Z`). */
challengeTimestamp: rest.challenge_ts,
/** Hostname of the website where the challenge was solved. */
hostname,
/** True if the response will be credited. @deprecated */
credit,
/** Error codes. @see {@link https://docs.hcaptcha.com/#siteverify-error-codes-table} */
errorCodes: rest["error-codes"],
/** Enterprise-only feature: score for malicious activity. */
score,
/** Enterprise-only feature: list of reasons for the malicious activity score. */
scoreReasons: rest["score-reason"],
})));
/**
`verifyHcaptchaToken` verifies with the hCaptcha.com API that the response token obtained
from a user who solved a captcha challenge is valid.
@param token - required: the token obtained from the user who solved the captcha challenge
@param secretKey - required: the secret key for your account
@param siteKey - optional but recommended: the site key for the website hosting the captcha challenge
@param remoteIp - optional: the IP address of the user who solved the challenge
@returns a {@link HcaptchaResponse} with the verification result
*/
export async function verifyHcaptchaToken({ token, secretKey, siteKey, remoteIp, }) {
const form = new URLSearchParams();
form.append("response", token);
form.append("secret", secretKey);
if (siteKey)
form.append("sitekey", siteKey);
if (remoteIp)
form.append("remoteip", remoteIp);
const response = await fetch("https://api.hcaptcha.com/siteverify", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: form.toString(),
});
const json = await response.json();
return hCaptchaResponseSchema.parse(json);
}