Skip to content

siteverify

siteverify gives you a server-to-server verification shape similar to reCAPTCHA. It is useful when the verifier runs as a separate API service instead of inside the same process as your app. The signing secret is server-held only. Clients never send it in the request body.

When to use siteverify vs verifyToken

siteverifyverifyToken
Use caseServer-to-server verification over HTTPDirect in-process verification
Secret managementServer-held secret in verifier optionsSingle secret in config
Input validationChecks for missing fields before verificationAssumes valid input
Response formatIncludes decoded claimsReturns { valid, score: 0, error? }

Use siteverify when your backend calls a Cerno API endpoint. Use verifyToken when Cerno runs in-process.

Request format

interface SiteverifyRequest {
token: string
session_id: string
}

Both required fields must be present or the call returns an error immediately.

Response format

interface SiteverifyResult {
success: boolean
score: number
challenge_id?: string
session_id?: string
site_key?: string
error?: string
}

Success response

{
"success": true,
"score": 0,
"challenge_id": "550e8400-e29b-41d4-a716-446655440000",
"session_id": "user-session-id",
"site_key": "your-site-key"
}

Failure response

{
"success": false,
"score": 0,
"error": "token_expired"
}

Usage

As an HTTP endpoint

Expose siteverify as a POST /siteverify route:

import { siteverify } from '@cernosh/server'
app.post('/siteverify', async (req, res) => {
const result = await siteverify({
token: req.body.token,
session_id: req.body.session_id,
}, {
secret: process.env.CERNO_SECRET!,
store,
})
res.json(result)
})

If you expose this route publicly, require an operator auth header. The checked-in worker supports CERNO_SITEVERIFY_AUTH_TOKEN and expects Authorization: Bearer <token>.

Calling from your backend

const response = await fetch('https://your-cerno-endpoint/siteverify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.CERNO_SITEVERIFY_AUTH_TOKEN}`,
},
body: JSON.stringify({
token: clientToken,
session_id: userSessionId,
}),
})
const result = await response.json()
if (!result.success) {
// reject the request
}

Key rotation

Pass an array of versioned signing keys in the verifier options to support key rotation without downtime. The function tries each key until one validates:

const result = await siteverify(
{
token: clientToken,
session_id: userSessionId,
},
{
secret: currentSecret,
secrets: [
{ kid: 'v2', value: currentSecret },
{ kid: 'v1', value: previousSecret },
],
store,
},
)