HMAC Verifier
security.verify_hmac
Overview
You pass the message, shared secret, and signature; we recompute the HMAC and compare it in constant time. A mismatch is a successful result with valid=false — not an error. We never echo the key or return partial-match information. Do not use this for JWT validation, password verification, or provider-specific header parsing.
Signature verification written by hand is where authentication quietly breaks — ordinary string comparison leaks timing, and an agent cannot recompute an HMAC reliably.
Reliability
STRICT and fully deterministic. The comparison is constant-time, so how long we take never depends on how much of your signature was correct, and a wrong code comes back as valid=false rather than as a failure. Your key is never echoed, logged, or referenced in any output or error field. HMAC_ALGORITHM_UNSUPPORTED — trigger: you named an algorithm outside HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512; retryable: no; next: pick one of those three and call again. HMAC_ENCODING_UNSUPPORTED — trigger: messageEncoding or keyEncoding was something other than utf8, hex or base64, or signatureEncoding was something other than hex, base64 or base64url; retryable: no; next: correct the named field. HMAC_KEY_INVALID_ENCODING — trigger: your key string does not parse as the keyEncoding you declared, for example odd-length hex; retryable: no; next: fix the key text or the declared encoding. HMAC_KEY_EMPTY — trigger: the key decoded to zero bytes, which happens with an empty hex or base64 string; retryable: no; next: send a key with at least one byte. HMAC_MESSAGE_INVALID_ENCODING — trigger: the message does not parse as the messageEncoding you declared; retryable: no; next: send valid hex or base64, or switch messageEncoding to utf8. HMAC_SIGNATURE_INVALID_ENCODING — trigger: the signature text is not valid under signatureEncoding, so we could not even decode it to compare; retryable: no; next: check whether the sender uses hex, base64 or base64url and declare that. Input validation (not retryable): missing message, key or signature; an empty key or signature string; any of them longer than the documented maximum.
Context footprint
Three scalar fields replace a cryptographic check an agent cannot perform and must not approximate. A successful call costs 1 execution credit.
When to use it
When you hold the shared secret and need to decide whether an inbound message carries a valid authentication code.
When the signature arrives inside a provider-specific header, when the token is a JWT, or when the credential is a password.
Scope
Non-goals
- Does not tell you why a signature failed beyond match / mismatch / length mismatch
- Does not return the expected signature, a matching-prefix length, or a byte offset
- Does not manage, derive, rotate, or store keys
- Does not check a timestamp, nonce, or replay window
- Does not parse provider-specific signature headers (use network.validate_webhook_signature)
- Does not verify asymmetric signatures (RSA, ECDSA, Ed25519) or JWTs
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill is designed to detect, mask, redact, validate, or otherwise process sensitive data.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- Targets sensitive data
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| message | string | Yes | Message covered by the code. |
| key | string | Yes | Secret shared key; never projected. |
| signature | string | Yes | Authentication code to verify. |
| algorithm | string | No | HMAC algorithm; omit it for HMAC-SHA256. |
| messageEncoding | string | No | Input byte encoding; omit it for utf8. |
| keyEncoding | string | No | Input byte encoding; omit it for utf8. |
| signatureEncoding | string | No | Code encoding; omit it for hex. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| valid | boolean | Yes | Whether the full code matches. |
| reason | string | Yes | Non-oracular verification reason. |
| algorithm | string | Yes | Applied HMAC algorithm. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"security.verify_hmac","input":{"message":"hello world","key":"secret","signature":"734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a"}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("security.verify_hmac", {"signature":"734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a","key":"secret","message":"hello world"});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| HMAC_ALGORITHM_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| HMAC_KEY_INVALID_ENCODING | 400 | No | The request payload failed this skill's input validation. |
| HMAC_KEY_EMPTY | 400 | No | The request payload failed this skill's input validation. |
| HMAC_MESSAGE_INVALID_ENCODING | 400 | No | The request payload failed this skill's input validation. |
| HMAC_SIGNATURE_INVALID_ENCODING | 400 | No | The request payload failed this skill's input validation. |
| HMAC_ENCODING_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not tell you why a signature failed beyond match / mismatch / length mismatch
- Does not return the expected signature, a matching-prefix length, or a byte offset
- Does not manage, derive, rotate, or store keys
- Does not check a timestamp, nonce, or replay window
- Does not parse provider-specific signature headers (use network.validate_webhook_signature)
- Does not verify asymmetric signatures (RSA, ECDSA, Ed25519) or JWTs
- Verifying a JWT (use security.validate_jwt)
- Verifying a password (use security.password_verify)
- Parsing a provider-specific signature header format before comparison
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "security.verify_hmac",
"input": {
"signature": "734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a",
"key": "secret",
"message": "hello world"
}
}Examples
Signature matches
{
"signature": "734cc62f32841568f45715aeb9f4d7891324e6d948e4c6c60c0621cdac48623a",
"key": "secret",
"message": "hello world"
}{
"algorithm": "HMAC-SHA256",
"valid": true,
"reason": "match"
}Signature does not match
{
"signature": "0000000000000000000000000000000000000000000000000000000000000000",
"key": "secret",
"message": "hello world"
}{
"algorithm": "HMAC-SHA256",
"valid": false,
"reason": "signature_mismatch"
}Recommended use cases
- Check the signature on an inbound webhook before acting on its body
- Authenticate a signed API request received from a partner
- Confirm a message was not modified in transit over an untrusted channel
Avoid for
- Verifying a JWT (use security.validate_jwt)
- Verifying a password (use security.password_verify)
- Parsing a provider-specific signature header format before comparison
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.