testServiceAuthIsForOneServer

tcmts.atproto.test.testServiceAuthIsForOneServer · #swbnpbwh · function

A service-auth token signs its account in to the one server it's for: checked against the account's key (a P-256 one, or a legacy secp256k1 one), it's refused by any other server, for another method, once it's expired, or changed at all.

import { configure, serviceDid, signInWithAppPassword, verifyServiceAuth } from "#codebase/tcmts/atproto";
import { fakeNetwork } from "#codebase/tcmts/atproto/testing";
import assert from "node:assert/strict";

export const testServiceAuthIsForOneServer = async () => {
  const alice = {
    did: "did:plc:alice000000000000000000",
    handle: "alice.test",
    password: "a-pass",
  };
  const bob = {
    did: "did:plc:bob00000000000000000000",
    handle: "bob.test",
    password: "b-pass",
    legacyKey: true,
  };
  const net = await fakeNetwork([alice, bob]);
  configure(net.config);
  try {
    const here = serviceDid("https://tcm.example/some/path");
    assert.equal(here, "did:web:tcm.example");
    // (a port only on localhost, as a PDS takes them: this machine's addresses are all localhost)
    for (const local of [
      "http://127.0.0.1:7737",
      "http://localhost:7737/forge",
      "http://[::1]:7737",
    ])
      assert.equal(serviceDid(local), "did:web:localhost%3A7737", local);
    assert.throws(() => serviceDid("https://tcm.example:8443"), /needs an address without one/);
    const token = async (
      who: typeof alice,
      o: { aud?: string; lxm?: string; exp?: number } = {},
    ) => {
      const s = await signInWithAppPassword(who.handle, who.password);
      return s.serviceAuth({
        aud: o.aud ?? here,
        lxm: o.lxm ?? "app.example.call",
        exp: o.exp ?? Date.now() + 60_000,
      });
    };
    const check = (jwt: string) =>
      verifyServiceAuth(jwt, { audiences: [here], lxm: "app.example.call" });
    assert.equal(await check(await token(alice)), alice.did);
    assert.equal(await check(await token(bob)), bob.did, "a legacy secp256k1 key");
    await assert.rejects(
      check(await token(alice, { aud: serviceDid("https://elsewhere.example") })),
      /the token is for did:web:elsewhere\.example, not this server \(did:web:tcm\.example\)/,
    );
    await assert.rejects(
      check(await token(alice, { lxm: "app.example.other" })),
      /not app\.example\.call/,
    );
    await assert.rejects(check(await token(alice, { exp: Date.now() - 5_000 })), /expired/);
    // the same claims said to be bob's: his key didn't sign them
    const [h, p, sig] = (await token(alice)).split(".");
    const claims = JSON.parse(Buffer.from(p!, "base64url").toString());
    const swapped = Buffer.from(JSON.stringify({ ...claims, iss: bob.did })).toString("base64url");
    await assert.rejects(check(`${h}.${swapped}.${sig}`), /isn't signed by did:plc:bob/);
    await assert.rejects(check("not.a-token"), /isn't a service-auth token/);
  } finally {
    configure({
      plc: undefined,
      appview: undefined,
      allowLocalNetwork: undefined,
      jetstream: undefined,
      relay: undefined,
    });
    await net.close();
  }
}

uses