Skip to content

Support a temporary dynamic web server #48

Description

@cfjedimaster

This could work and it's my fault but - I'm attempting to add an oauth flow to a tinyjs app. While you can register custom url schemes with the app, Google no longer supports custom schemes, so the suggestion is to fire up a temp local server that would render something like:

You are now logged in. Close this tab.

My agent attempted to build this in the back end code like so:

const enc = new TextEncoder();
const dec = new TextDecoder();

async function waitForCode(port, expectedState) {
  console.log('waitForCode', port, expectedState);
  const listener = await tjs.listen("tcp", "127.0.0.1", port);
  const timer = setTimeout(() => listener.close(), 120000); // give up after 2 min

  try {
    while (true) {
      const conn = await listener.accept();
      const buf = new Uint8Array(8192);
      const n = await conn.read(buf);
      const firstLine = dec.decode(buf.subarray(0, n)).split("\r\n")[0]; // GET /callback?code=... HTTP/1.1
      console.log('firstLine', firstLine);
      const url = new URL(firstLine.split(" ")[1] || "/", `http://127.0.0.1:${port}`);
      const isCallback = url.pathname === "/callback";

      const body = isCallback ? "<h3>Login complete. You can close this tab.</h3>" : "";
      await conn.write(enc.encode(
        `HTTP/1.1 ${isCallback ? "200 OK" : "404 Not Found"}\r\n` +
        `Content-Type: text/html\r\nContent-Length: ${enc.encode(body).length}\r\n` +
        `Connection: close\r\n\r\n${body}`
      ));
      conn.close();

      if (!isCallback) continue; // e.g. /favicon.ico

      const err = url.searchParams.get("error");
      if (err) throw new Error(err);
      if (url.searchParams.get("state") !== expectedState) throw new Error("state mismatch");
      return url.searchParams.get("code");
    }
  } finally {
    clearTimeout(timer);
    listener.close();
  }
}

export const api = {
  waitForCode: ({ port, state }) => waitForCode(port, state),
};

And I added logic on the front end to call this. I can confirm it gets run, but when my oauth test fails, I get a site cannot be reached error in the browser which means the app isn't really listening (from what I can see).

Any ideas?

Activity

  1. tarwin commented on Oct 9, 2026

    @tarwin
    Owner

    @cfjedimaster the "platter" example hopefully can give you some insight. It uses a loopback server for similar auth (Spotify Connect). The big thing to see is that there is a tjs.serve which does what you are looking for I think?

    const server = tjs.serve({
      port: 8898,
      fetch: async (req) => {
        const u = new URL(req.url);
        if (u.pathname !== '/callback') return new Response('', { status: 404 });
        // check state, take code, then close the server shortly after
        return new Response('<h3>Login complete. You can close this tab.</h3>',
          { headers: { 'content-type': 'text/html' } });
      },
    });
    // later: server.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions