Offline Validation
Offline Validation refers to confirming a solution is valid to minimize calls to the siteverify API with solutions that are malformed, expired or otherwise invalid. It does not replace the siteverify API because a valid solution makes no humanity assertion.
Offline Validation is optional but recommended to prevent getting ratelimited.
For debugging, we recommend using this webpage: https://dinochiesa.github.io/jwt/
Solution format
After a user solves the challenge, a JWT is issued (referred to as solution). The JWT payload contains the following claims:
Custom claims are prefixed with #
, see Custom claims. The
##
claim is encrypted, see Encrypted claims.
Validate a solution
To validate a solution, you must obtain the correct public key from our API.
Extract the kid
from the JWT header and find the corresponding key in the JWK
set. Then, use the key to validate the JWT signature.
All of the following must be true for a solution to be valid:
- The JWT signature is valid
- The JWT signature algorithm is
RS256
(also found in the JWT header) - The JWT
iss
claim isglobal.captcha.party
(or the region you are using) - The JWT
aud
claim is your sitekey - The JWT
exp
claim is in the future - The JWT
nbf
claim is in the past
Additionally you may choose to validate any or all of the custom claims:
- The JWT
#url
claim matches the URL of the page where the challenge was solved - The JWT
#data
claim matches the data value you are expecting (requires Professional plan) - The JWT
#action
claim matches the action value you are expecting (requires Business plan) - The JWT
#ip
claim matches the hashed IP of the user - The JWT
#ua
claim matches the hashed User-Agent of the user
Obtaining the public key
The public key is a JSON Web Key (JWK) and can be obtained from the following endpoint: https://captcha.party/.well-known/jwks.json
The JWK set contains a list of keys. Each key has a kid
property. The kid
property is a unique identifier for the key. You can find the kid
of the key
you need in the JWT header.
We regularly rotate the keys in the JWK set. However, we will not use new keys for at least 4 weeks, so you can cache the JWK set for up to one week.
Preventing replay attacks
The jti
claim is a unique identifier for the solution. It is a UUID and is
generated by the server. It is used to prevent replay attacks. If you receive a
solution with a jti
that you have already seen, you should reject it. You only
need to store jti
values for a short period of time (until the exp
claim
expires).
Difference between iat
and nbf
The iat
claim is the time when the challenge was solved, and the nbf
claim
is the time when the challenge started. You can use the difference between these
two values to determine how long it took the user to solve the challenge.
You can also use the nbf
claim to prevent CAPTCHAs from being loaded before a
certain time. For example, if you have a sale that starts at 12:00
and
requires a CAPTCHA, you shouldn’t be allowing solutions from 11:59
, as a human
couldn’t have accessed the CAPTCHA yet.
Key rotation
We issue a new key at the start of every month and add it to the JWK set. We will not use new keys for at least 4 weeks, so you can cache the JWK set for up to one week.
Keys are in one of four states:
issued
- The key has been issued, is added to the JWK set but is not yet in use.active
- The key is currently in use for signing solutions.inactive
- The key is no longer in use for signing solutions, but is still in the JWK set.revoked
- The key is no longer in use for signing solutions and has been removed from the JWK set.
Each key will advance to the next state at the start of every month. For
example, a key that is issued
in January will become active
in February,
inactive
in March and revoked
in April.
Custom claims
Custom claims are prefixed with #
to prevent collisions with standard claims.
The following custom claims are available:
Claim | Description |
---|---|
#remoteip | The IP address of the user (hashed) |
#useragent | The user agent of the user (hashed) |
#url | The URL of the page where the challenge was solved |
#data | The data value of the challenge (requires Professional plan) |
#action | The action value of the challenge (requires Business plan) |
Hashed claims
Some claims are hashed to protect the privacy of the user. The hash is a HMAC hash (using SHA-256) with only the first 2 bytes used (to prevent bruteforce attacks at the expense of opening up collision attacks).
To validate a hashed claim, HMAC the value of the claim with your secret key and compare the first 2 bytes of the result with the value of the claim.
For example, to validate the IP address, concatenate the IP address with your
secret key and compare the SHA-256 hash of the result with the value of the
#remoteip
claim.
Encrypted claims
There are additional claims that are encrypted to protect the integrity of our service.
Enterprise customers can decrypt these claims using the decryption key provided to them using Offline Verification.