All skills
upstash avatar

/upstash-qstash-js

@36daab8
by upstashupstash/skills27 stars
7

Work with the @upstash/qstash TypeScript/JavaScript SDK, an HTTP-based message queue, task scheduler, and background job system for serverless and edge runtimes (Next.js, Vercel, Cloudflare Workers, Deno, Node.js). Use when publishing messages to HTTP endpoints or URL groups, running background jobs without a long-running worker process, scheduling with cron expressions, delaying messages, building FIFO queues with parallelism and flow control, configuring retries and callbacks, handling a dead letter queue (DLQ), deduplicating messages, fanning out to multiple endpoints, verifying QStash webhook signatures (Next.js App Router, Pages Router, and Edge Runtime), running a local QStash dev server, or migrating regions. Also use when the user asks for a serverless cron job, async task queue, job scheduler, delayed delivery, webhook delivery with retries, or event-driven messaging between services.

Use this Skill: https://skilld.dev/gh/upstash/skills/upstash-qstash-js

This session only. Nothing lands on disk.

verificationreceiver.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Receiver - Message Verification

Overview

The Receiver class verifies that incoming requests are genuinely from QStash by validating JWT signatures. This prevents unauthorized requests from reaching your endpoints.

Getting Your Signing Keys

Sign in to the Upstash Console and navigate to your QStash instance to find:

  • Current Signing Key: Active key for signature verification
  • Next Signing Key: Key to use after rotation

Store these as environment variables:

QSTASH_CURRENT_SIGNING_KEY="your_current_key"
QSTASH_NEXT_SIGNING_KEY="your_next_key"

Creating a Receiver Instance

Basic Setup

import { Receiver } from "@upstash/qstash";

const receiver = new Receiver({
  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
});

Multi-Region Mode

If you're using multi-region QStash (with QSTASH_REGION environment variable set), signature verification requires additional configuration. The SDK automatically detects the region from the upstash-region header and uses region-specific signing keys.

Important: Multi-region signature verification requires careful setup. See Multi-Region Setup for complete details on environment variables, region detection, and verification strategies.

Verifying Incoming Requests

Basic Verification

try {
  await receiver.verify({
    signature: request.headers.get("upstash-signature")!,
    body: await request.text(),
  });

  // Request is valid - process it
  return new Response("OK", { status: 200 });
} catch (error) {
  // Invalid signature
  return new Response("Unauthorized", { status: 401 });
}

With URL Verification

For extra security, verify the request was sent to the correct URL:

await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body: await request.text(),
  url: "https://my-api.example.com/webhook",
});

With Clock Tolerance

Handle minor clock differences between servers:

await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body: await request.text(),
  clockTolerance: 5, // Allow 5 seconds difference
});

Required Headers

QStash sends these headers with every request:

  • Upstash-Signature: JWT signature to verify

Note: In multi-region mode, QStash also sends an Upstash-Region header. See Multi-Region Setup for details.

Handling Verification Failures

SignatureError

The verify() method throws SignatureError for invalid signatures:

import { Receiver, SignatureError } from "@upstash/qstash";

try {
  await receiver.verify({
    signature: request.headers.get("upstash-signature")!,
    body: await request.text(),
  });
} catch (error) {
  if (error instanceof SignatureError) {
    console.error("Invalid signature:", error.message);
    return new Response("Invalid signature", { status: 401 });
  }
  throw error;
}

Common Failure Reasons

  1. Missing or wrong signing keys

    • Verify keys in Upstash Console match environment variables
  2. Body mismatch

    • Ensure you pass the raw request body (not parsed JSON)
    • Don't modify the body before verification
  3. Expired signature

    • QStash signatures expire after 5 minutes
    • Check server clock is synchronized
    • Use clockTolerance if needed
  4. URL mismatch

    • Ensure the url parameter matches the destination URL
    • Include protocol, domain, and path

Key Rotation

The Receiver supports seamless key rotation:

  1. Verification tries currentSigningKey first
  2. If that fails, tries nextSigningKey
  3. Only throws error if both fail

To rotate keys:

  1. Set new key as QSTASH_NEXT_SIGNING_KEY
  2. Wait for all in-flight requests to complete
  3. Update QSTASH_CURRENT_SIGNING_KEY to the new key
  4. Generate a new QSTASH_NEXT_SIGNING_KEY

Best Practices

Always Verify

Never trust incoming requests without verification:

// ❌ Don't do this
app.post("/webhook", async (req) => {
  const data = await req.json();
  processWebhook(data); // Unverified!
});

// ✅ Do this
app.post("/webhook", async (req) => {
  const body = await req.text();

  await receiver.verify({
    signature: req.headers.get("upstash-signature")!,
    body,
  });

  const data = JSON.parse(body);
  processWebhook(data);
});

Use Environment Variables

Never hardcode signing keys:

// ❌ Don't do this
const receiver = new Receiver({
  currentSigningKey: "sig_abc123...",
});

// ✅ Do this
const receiver = new Receiver({
  currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
  nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
});

Read Body Once

Request bodies can only be read once. Save it for reuse:

const body = await request.text();

// Verify with raw body
await receiver.verify({
  signature: request.headers.get("upstash-signature")!,
  body,
});

// Parse after verification
const data = JSON.parse(body);

Platform-Specific Verification

For framework-specific implementations, see:

Source: SKILL.md on GitHub

No alerts17d3 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    The skill provides comprehensive documentation and implementation guides for the Upstash QStash JS SDK. It includes a local development feature that automatically downloads and executes the official QStash CLI binary. While this involves remote code download and execution, it originates from the trusted vendor. The skill also processes external webhooks, creating a surface for indirect prompt injection, which is mitigated by built-in signature verification instructions.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

Signed by skilld at 36daab8. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 5 days ago.

Activeupdated last month
metadata
{
  "author": "Upstash",
  "homepage": "https://upstash.com"
}

README badge

README badge for upstash/skills/upstash-qstash-js