HTTP Requests with Server Workers

HTTP requests are the simplest way to communicate with Server Workers. While they don't provide all the features of JazzRPC, they are a good solution when all you need is basic authentication.

They work by generating a short-lived token with generateAuthToken and attaching it to the request headers as Authorization: Jazz <token>. The server can then verify the token with authenticateRequest and get the account that the request was made by.

Note

While the token is cryptographically secure, using non secure connections still makes you vulnerable to MITM attacks as - unlike JazzRPC - the request is not signed.

Replay attacks are mitigated by token expiration (default to 1 minute), but it's up to you to ensure that the token is not reused.

It is recommended to use HTTPS whenever possible.

Creating a Request

You can use any method to create a request; the most common is the fetch API.

By default, the token is expected to be in the Authorization header in the form of Jazz <token>.

import { generateAuthToken } from "jazz-tools";

const response = await fetch("https://example.com", {
  headers: {
    Authorization: `Jazz ${generateAuthToken()}`,
  },
});

Authenticating requests

You can use the authenticateRequest function to authenticate requests.

Attempting to authenticate a request without a token doesn't fail; it returns account as undefined. For endpoints that require authentication, ensure account is defined in addition to any permission checks you may need.

import { authenticateRequest } from "jazz-tools";
import { startWorker } from "jazz-tools/worker";

export async function GET(request: Request) {
  const worker = await startWorker({
    syncServer: "wss://cloud.jazz.tools/?key=your-api-key",
    accountID: process.env.JAZZ_WORKER_ACCOUNT,
    accountSecret: process.env.JAZZ_WORKER_SECRET,
    asActiveAccount: true,
  });

  const { account, error } = await authenticateRequest(request);

  // There was an error validating the token (e.g., invalid or expired)
  if (error) {
    return new Response(JSON.stringify(error), { status: 401 });
  }

  if (!account) {
    return new Response("Unauthorized", { status: 401 });
  }

  return new Response(
    JSON.stringify({
      message: `The request was made by ${account.$jazz.id}`,
    }),
  );
}

Multi-account environments

If you are using multiple accounts in your environment - for instance if your server starts multiple workers - or in general if you need to send and authenticate requests as a specific account, you can specify which one to use when generating the token or when authenticating the request.

Making a request as a specific account

generateAuthToken accepts an optional account parameter, so you can generate a token for a specific account.

const response = await fetch("https://example.com", {
  headers: {
    Authorization: `Jazz ${generateAuthToken(account)}`,
  },
});

Authenticating a request as a specific account

Similarly, specify the account used to verify the token via the loadAs option:

import { authenticateRequest } from "jazz-tools";
import { startWorker } from "jazz-tools/worker";

export async function GET(request: Request) {
  const { worker } = await startWorker({
    syncServer: "wss://cloud.jazz.tools/?key=your-api-key",
    accountID: process.env.JAZZ_WORKER_ACCOUNT,
    accountSecret: process.env.JAZZ_WORKER_SECRET,
  });

  const { account, error } = await authenticateRequest(request, {
    loadAs: worker,
  });
}

Custom token expiration

You can specify the expiration time of the token using the expiration option. The default expiration time is 1 minute.

import { authenticateRequest } from "jazz-tools";

export async function GET(request: Request) {
  const { account, error } = await authenticateRequest(request, {
    expiration: 1000 * 60 * 60 * 24, // 24 hours
  });
}

Custom token location

While using the Authorization header using the Jazz <token> format is the most common way to send the token, you can provide the token in any other way you want.

For example, you can send the token in the x-jazz-auth-token header:

import { generateAuthToken } from "jazz-tools";

const response = await fetch("https://example.com", {
  headers: {
    "x-jazz-auth-token": generateAuthToken(),
  },
});

Then you can specify the location of the token using the getToken option:

import { authenticateRequest } from "jazz-tools";

export async function GET(request: Request) {
  const { account, error } = await authenticateRequest(request, {
    getToken: (request) => request.headers.get("x-jazz-auth-token"),
  });
}

Manual token parsing

If you need to manually parse a token from a string, you can use the parseAuthToken function.

import { parseAuthToken, generateAuthToken } from "jazz-tools";

const myToken = generateAuthToken();

const { account, error } = await parseAuthToken(myToken);