Gemini JWKS JWT webhook signatures vs Sume HMAC SHA-256

Gemini dynamic webhooks use asymmetric JWKS-signed JWTs. Sume signs the raw body with a shared-secret HMAC SHA-256 and a timestamp. How each verifies.

4 min readSume
All posts

Gemini dynamic webhooks emit a JSON Web Token signature that you verify against Google's public keys (JWKS). Sume uses a symmetric scheme instead: it signs the raw JSON body with HMAC SHA-256 over <timestamp>.<raw_body> using your workspace secret. You recompute the HMAC and compare it; there is no key fetch.

Sources: the Gemini Webhooks page and Sume's Webhooks docs, read 2026-10-01.

How does Gemini's dynamic signature check work?

The page says dynamic webhooks use asymmetric public-key JWKS signatures instead of symmetric secrets. Your listener extracts the signature, finds the matching key, and verifies the JWT; its sample errors include "No signature header", "Failed to fetch JWKS" and "Matching key not found". Static webhooks use a stored static signing secret.

What does a Sume verifier check?

Two headers: x-sume-webhook-timestamp and x-sume-webhook-signature: sume-v1=<hex_signature>. Sign the exact bytes you received, not re-serialized JSON. During secret rotation the header lists one sume-v1= entry per live secret, so accept the delivery when any entry matches.

Verification steps, Gemini dynamic vs Sume, read 2026-10-01.
StepGemini dynamic webhookSume webhook
Key materialPublic JWKS keysShared workspace secret
Signature formatJWTsume-v1=<hex> HMAC SHA-256
Signed inputPer JWT<timestamp>.<raw_body>
Network call to verifyFetch the JWKSNone

How do I stop replayed deliveries?

Reject callbacks whose timestamp is outside your replay tolerance window; the docs call five minutes a reasonable default. Gemini's page also advises validating a timestamp header to reject old payloads.

Do I have to write the verifier myself?

Not in TypeScript: @sume-com/sdk ships verifyWebhook, which checks the sume-v1 signature and the replay window, and is async, so await it. A missing await makes the result an always-truthy promise; see that pitfall. Whatever you use, refuse to verify when the secret is empty.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume