paperclipai/paperclip · error
Cloud runtime identity signature is invalid
Error message
Cloud runtime identity signature is invalid
What it means
Thrown by verifyClaims when the Ed25519 signature over header.payload does not verify against the public key selected by kid from the JWKS. node:crypto's verify() returned false, meaning the signed bytes were altered, signed with a different key, or the signature bytes were corrupted.
Source
Thrown at server/src/services/cloud-runtime-identity.ts:283
const parts = input.compactJws.split(".");
if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
throw new Error("Cloud runtime identity assertion is not a compact JWS");
}
const [encodedHeader, encodedPayload, encodedSignature] = parts;
const header = decodeJsonPart(encodedHeader, "protected header");
if (
header.alg !== "EdDSA"
|| header.typ !== CLOUD_RUNTIME_IDENTITY_JWS_TYPE
|| typeof header.kid !== "string"
|| !header.kid
) {
throw new Error("Cloud runtime identity protected header is invalid");
}
const key = publicKeyForKid(input.env, header.kid);
const signature = Buffer.from(encodedSignature, "base64url");
const signingInput = Buffer.from(`${encodedHeader}.${encodedPayload}`, "ascii");
if (!verify(null, signingInput, key, signature)) {
throw new Error("Cloud runtime identity signature is invalid");
}
const payload = decodeJsonPart(encodedPayload, "payload");
const nowSeconds = Math.floor(input.now.getTime() / 1000);
if (
payload.v !== 1
|| payload.iss !== CLOUD_RUNTIME_IDENTITY_ISSUER
|| payload.aud !== CLOUD_RUNTIME_IDENTITY_AUDIENCE
|| typeof payload.sub !== "string"
|| typeof payload.claimId !== "string"
|| typeof payload.previousOrigin !== "string"
|| typeof payload.canonicalOrigin !== "string"
|| typeof payload.stackSlug !== "string"
|| typeof payload.iat !== "number"
|| !Number.isInteger(payload.iat)
|| typeof payload.exp !== "number"
|| !Number.isInteger(payload.exp)
) {View on GitHub (pinned to 01ad858492)
Solutions
- Re-issue the assertion from the Cloud control plane; never modify any segment of a signed token
- Ensure the signing key corresponds to the public key published in PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS under the same kid
- Transmit the token verbatim (no trimming/re-encoding beyond whitespace) — do not normalize case or padding
- Verify the token with the same environment's JWKS (staging token against staging JWKS)
Example fix
// before: editing payload without re-signing
const tampered = parts[0] + "." + b64url({...claims, exp: 9999999999}) + "." + parts[2];
// after: re-mint the assertion server-side with the private key
const fresh = await controlPlaneClient.mintIdentityAssertion(stackId); Defensive patterns
Strategy: try-catch
Try / catch
try {
verifyCloudRuntimeIdentityAssertion({ compactJws: assertion, expectedPreviousOrigin: prev });
} catch (e) {
if (String((e as Error).message).includes("signature is invalid")) {
logger.warn("Identity assertion signature check failed; fetching a fresh assertion", { error: e });
const fresh = await controlPlaneClient.mintIdentityAssertion(stackId); // retry once with a new token
} else throw e;
} Prevention
- Never mutate any segment of a signed token (including 'harmless' claim edits) — always re-sign
- Ensure signer private key and verifier JWKS are a matched pair per kid and environment
- Transmit tokens through channels that don't rewrite content (avoid HTML encoding, line wrapping)
- Keep a single canonical base64url implementation for mint and verify
When it happens
Trigger: The signingInput (encodedHeader + '.' + encodedPayload) differs from what was signed (payload edited, whitespace inserted, re-encoding changed), the token was signed with a private key not corresponding to the JWKS entry for header.kid, or the signature segment was truncated/mangled in transit.
Common situations: Manually editing claims (e.g. extending exp) without re-signing; signing with the wrong environment's private key; token passed through a proxy that rewrites case or padding; mixing base64 and base64url encodings when re-serializing.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS is not configured
- Cloud runtime identity uses an unknown signing key
- Cloud runtime identity signing key is invalid
- Cloud runtime identity protected header is invalid
- Cloud runtime identity claims are incomplete
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/beb002c934feacf3.
Report an issue: GitHub.