verify-hcaptcha
Version:
A fully typed library to verify hCaptcha.com tokens submitted by users when solving captcha challenges
80 lines (79 loc) • 2.9 kB
JavaScript
// src/index.ts
import { z } from "zod";
var hCaptchaResponseSchema = z.object({
success: z.boolean(),
challenge_ts: z.string().optional(),
hostname: z.string().optional(),
credit: z.boolean().optional(),
"error-codes": z.array(
z.union([
/** Secret key is missing. */
z.literal("missing-input-secret"),
/** Secret key is invalid. */
z.literal("invalid-input-secret"),
/** User response token is missing. */
z.literal("missing-input-response"),
/** User response token is invalid. */
z.literal("invalid-input-response"),
/** Site key is invalid. */
z.literal("invalid-sitekey"),
/** Remote user IP is missing. */
z.literal("missing-remoteip"),
/** Remote user IP is invalid. */
z.literal("invalid-remoteip"),
/** Request is invalid. */
z.literal("bad-request"),
/** User response token is invalid or has already been checked. */
z.literal("invalid-or-already-seen-response"),
/** Must use the test site key when using a test verification token. */
z.literal("not-using-dummy-passcode"),
/** Must use the test secret key when using a test verification token. */
z.literal("not-using-dummy-secret"),
/** The site key is not associated to the secret key. */
z.literal("sitekey-secret-mismatch")
])
).optional(),
score: z.number().optional(),
"score-reason": z.array(z.string()).optional()
}).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"]
}));
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);
}
export {
verifyHcaptchaToken
};