# Install "Sign in with qID" — release pack

You're holding the qID Connect release pack: everything a BTX dApp needs to add
**wallet login** — one button, one server middleware, the address IS the
account. No email, no password, no relay server. A qID sign-in proof can never
move funds (login and transactions sign in different cryptographic domains).

> **Fastest path:** you don't even need this zip to try it. Add the hosted
> widget in two lines (below), point it at your `/qid` endpoints, done. The zip
> gives you the server SDK, runnable examples, the test signer, and the docs.

---

## What's in this pack

```
packages/server     @qid/connect-server   challenge, verify (frozen v1), sessions,
                                          accounts-by-address, durable SQLite stores
packages/widget     @qid/connect-widget   the "Sign in with qID" button + dialog
examples/express-demo        a complete wallet-only login site (run it, crib it)
examples/next-demo           the same as Next.js drop-in files
examples/static-rewrite-demo a standalone server for a CDN page + same-origin rewrite
tools/signer                 the reference signer CLI — develop with no wallet installed
docs/INTEGRATION.md          the full guide          docs/DESIGN.md  the design contract
docs/MIGRATION-from-email.md CHANGELOG.md            SECURITY.md
```

## Install in three steps (about an hour, most of it reading)

### 1. The button (frontend)

Easiest — the **hosted** widget. Nothing to vendor; UI/wallet-list updates reach
your users automatically, and the signed protocol underneath is frozen v1 so an
update can never break your login:

```html
<div id="signin"></div>
<script type="module">
  import { mountQidConnect } from "https://qid.dev/connect/widget.js";
  mountQidConnect(document.getElementById("signin"), {
    api: "/qid",                    // "/api/qid" on Next.js
    appName: "Your app",
    onSignedIn({ address, account }) { location.reload(); },
  });
</script>
```

Prefer to pin exact bytes? Copy `packages/widget/src/` from this pack instead
(a version-pinned hosted copy exists too: `widget-<version>.js`).

**The signed-in chip (recommended).** Once a user is in, drop
`mountQidAccount` wherever your header/nav lives so the signed-in state looks
the same on every BTX app — a compact chip (green dot + address) that opens a
dropdown with the address (click to copy) and **Log out** (a deliberate
two-step, never a one-click accident):

```html
<div id="signin"></div>    <!-- the Sign in button -->
<div id="account"></div>   <!-- the signed-in chip (in your header) -->
<script type="module">
  import { mountQidConnect, mountQidAccount } from "https://qid.dev/connect/widget.js";
  const account = mountQidAccount(document.getElementById("account"), {
    api: "/qid",
    onSignedOut() { location.reload(); },
    // menuItems: [ ... ]  // optional extra rows (e.g. future Bonuz ID socials)
    // explorer: (addr) => `https://btxscan.io/address/${addr}`,  // optional link
  });
  mountQidConnect(document.getElementById("signin"), {
    api: "/qid", appName: "Your app",
    onSignedIn() { account.refresh(); },   // show the chip with no reload
  });
</script>
```

`mountQidAccount` renders nothing when signed out, so it's safe to mount
unconditionally. It returns `{ refresh, unmount }`.

### 2. The server (backend)

Express — one middleware is the whole login system:

```js
import express from "express";
import { createQidConnect } from "@qid/connect-server";
import { qidMiddleware, requireQidSession } from "@qid/connect-server/express";

const qid = createQidConnect({
  origin: "https://www.yourapp.com",             // EXACT origin users land on
  sessionSecret: process.env.QID_SESSION_SECRET, // 32+ random chars
});
const app = express();
app.use(express.json());
app.use("/qid", qidMiddleware(qid));             // challenge/verify/poll/session/logout
app.get("/api/me", requireQidSession(qid), (req, res) => res.json(req.qidSession));
```

Next.js is one catch-all route file (`examples/next-demo/`). A **static site +
backend on another host** uses `examples/static-rewrite-demo/` (durable SQLite,
systemd unit, and same-origin rewrite recipes for Vercel / Netlify / Caddy /
nginx). `@qid/connect-server` lives in `packages/server` — add it as a workspace
dependency or vendor it (three small deps: `@noble/post-quantum`, `@noble/hashes`,
`@scure/base`).

### 3. See it, then test without a wallet

```sh
bun install
bun test packages                 # the whole surface — should be all green
bun examples/express-demo/server.js   # open http://localhost:8788 — a working login site
```

Develop with no wallet installed: click the button, then **switch to the
"Desktop wallet" tab first** — it shows the request text and, unlike the QR tab,
does not rotate while you work. Copy `nonce` and `ts` from step 1, then

```sh
bun tools/signer/btx-sign-ownership.mjs --random \
  --origin http://localhost:8788 --nonce <nonce> --ts <ts>
```

paste the printed proof into that same "Desktop wallet" tab's step 2 (or POST it
to `/qid/proof` to simulate a phone scanning the QR). Don't copy from the QR tab
and dawdle: the QR rotates about every 105s, and the server burns the old nonce,
so a proof you signed against it will be rejected as expired.

## The one thing that trips people up: `origin`

`origin` must be the **exact host users actually land on**, after any apex↔www or
http→https redirect your CDN does. If your site 308-redirects `example.com` →
`www.example.com`, set `origin: "https://www.yourapp.com"` — the apex value
silently rejects every proof with `bad_origin`. Open your live site and read
`location.origin` in the console; that exact string is your `origin`. The
`static-rewrite-demo` server even warns you at boot if you get this wrong.

## Wallets your users can bring

- **PQ Wallet for BTX** (desktop) — available now: paste since v0.21, one-click
  `btxqid://` connect since v0.27.
- **bonuz Wallet** (mobile) — available now: scan the qID QR with the bonuz
  app, pick your wallet, and you are in. Zero changes on your side.

## Ground rules

- The address is the account — don't bolt qID onto email accounts
  (`docs/MIGRATION-from-email.md`).
- Keep the button and dialog stock (`docs/DESIGN.md`) so "Sign in with qID"
  looks the same on every BTX app — that sameness is the trust.
- Serve over https with your exact origin; a same-origin `/qid/*` rewrite is
  fine (and required for the session cookie if your server is on another host);
  never change the origin the wallet sees.
- The code is MIT; the qID name and mark are not (`TRADEMARKS.md`).

## Using an AI coding assistant?

Paste this whole file plus `docs/INTEGRATION.md` into your assistant as the task
brief, point it at your codebase, and ask it to wire the button + the server
middleware and run the smoke test (`bun test packages`, then the express-demo).
Everything it needs is in this pack.

---

Full guide: **https://qid.dev/connect/integrate** · Live demo:
**https://qid.dev/connect** · User help: **https://qid.dev/connect/how**
You're an early integrator — anything rough, send it back and we fix it fast.
