invalid_signature
The signed JWT does not verify against the registered public key, or one of its claims does not match the request.
| HTTP | code | Retryable? |
|---|---|---|
| 401 | invalid_signature | no |
When it happens
Incorrect signature, sub/uri/bodyHash that do not match, exp - iat > 60s, or a missing nonce.
reason values
The response carries a reason field naming the first check that failed. Checks run in the order of the table below, so a bad_body_hash means sub and uri already matched. Branch on reason, not on detail.
reason | Meaning |
|---|---|
no_signing_key | The key has no active signing key. Upload the public key (SPKI) from the panel. |
bad_jwt | The JWT does not verify against any active signing key, or it is malformed or expired. We verify against all active keys, so this is not a rotation overlap. |
bad_sub | The sub claim is not identical to the X-API-Key header. Both are the key prefix. |
bad_uri_claim | The uri claim is not "METHOD /path?query" exactly as sent, query string included. |
missing_iat_exp | iat or exp is missing, or is not a number. |
exp_too_far | exp - iat > 60 seconds. |
bad_body_hash | bodyHash is not the SHA-256 hex of the raw bytes you sent. Serialize the body once and send those bytes. |
missing_nonce | The nonce claim is missing. A repeated nonce is a different error: nonce_reused. |
How to resolve it
Rebuild the JWT: sub = the key prefix, uri = the exact "METHOD /path?query", bodyHash = SHA-256 hex of the raw request body bytes, exp ≤ iat + 60. Sign with the private key whose public counterpart you uploaded.
Example
{
"type": "https://docs.skipo.com/errors/invalid_signature",
"title": "Invalid signature",
"status": 401,
"code": "invalid_signature",
"retryable": false,
"detail": "The signed JWT does not verify against the registered public key, or one of its claims does not match the request.",
"reason": "bad_sub"
}
Back to the error catalog · See the error format.