Check Sign-In on a Server
Share
Anything that matters is checked on the server, never by the kit. The kit and the data-kt-* attributes only hide things in the browser. If a page, file or API route is private, the server must refuse to send it.
The Limit Today
Section titled “The Limit Today”The KT Accounts session cookie (__Host-kt.session_token) is sent by browsers to accounts.aidenkt.com and to nothing else, so a site’s own server never receives it. That means:
- For a real server check, use OpenID Connect and keep your own session. This works today on any domain.
- The cookie-based helpers below return “nobody” on a real site, for everyone. They fail closed. They work against the local stand-in, and will work on real sites once KT Accounts can hand a site proof of who is signed in, which is proposed and not built.
The Helpers
Section titled “The Helpers”Single files with no dependencies, in the integrations/ folder of the KT Accounts repository. Copy them into the site.
| File | For |
|---|---|
kt-accounts.mjs (and kt-accounts.d.mts for TypeScript) |
Anything with fetch: Workers, Deno, Bun, Node 18+ |
kt-accounts-middleware.mjs |
Express and Hono. Needs kt-accounts.mjs next to it |
kt-accounts-next.mjs |
The Next.js app router. Needs kt-accounts.mjs next to it |
import { getKtUser, requireKtUser, has, hasBadge } from "./kt-accounts.mjs";
const kt = { origin: env.KT_ACCOUNTS_ORIGIN ?? "https://accounts.aidenkt.com" };
const user = await getKtUser(request, kt); // a person, or nullconst r = await requireKtUser(request, { ...kt, permission: "brand.materials" });if ("response" in r) return r.response; // 401 or 403, ready to sendgetKtUser(request, { origin })returns the person ornull.requestcan be aRequest, aHeaders, a Node request, or theCookieheader string.requireKtUser(request, { origin, permission?, badge? })returns{ user }or{ response }:401 {"error":"sign_in_required"}or403 {"error":"forbidden"}, both JSON withCache-Control: no-storeandVary: Cookie.has(user, name)follows the same rule asktAccounts.can: the owner has every permission.hasBadge(user, "friend")is true only if the person carries that badge.sendKtResponse(res, response)sends such a response through a Noderes.- Express:
ktExpress,requireKtExpress. Hono:ktHono,requireKtHono. Next.js:currentKtUser,ktMiddleware.
getKtUser sends only the KT session cookie to <origin>/api/whoami, gives up after 2 seconds, returns null on any failure, and keeps nothing between requests. origin must be exactly https://accounts.aidenkt.com or the stand-in on http://localhost:<port>; anything else throws a TypeError. The stand-in is refused when NODE_ENV is production.
People with the test badge are refused on an https origin unless you pass allowTest: true.
Never cache a response that depends on who is signed in: send Cache-Control: no-store. The guards do not protect against cross-site form posts; for routes that change something, also check the Origin header or use the framework’s CSRF protection.