Auth / foldkit-auth

Who the client believes it is

The cookie is the browser's, shared by every tab: a sign-in in one tab changes who another tab's next read is answered as. A broadcast between tabs tells the others, but a read already on its way would land the new account's answers in a cache that shows the old one. So the server says whom it answered as, and the client repeats it:

ts
import { believing } from 'foldkit-auth'

const resolving = { auth: AppAuth, http, principal, key: Policy.key }
serveFetch({
  server,
  resolvePrincipal: AuthServer.resolver(resolving),
  headers: AuthServer.answered(resolving), // `x-foldkit-subject` on each answer
  layer: () => AppAuthLive,
})

// The browser: Remote's transport through a fetch that repeats it.
export const belief = believing()
Remote.httpWithLive('/remote', {
  headers: () => ({ 'x-effect-auth-csrf': '1' }),
  fetch: belief.fetch,
})
  • AuthServer.answered takes the resolver's own config, and needs its key, so the header names the principal as the check reads it: subjectSaid(Option.some(key(user))), or visitor. The key is URI-encoded, as a header carries Latin-1 only.
  • believing() holds what the last answer said, beside the cookie it describes, never in the Model. Once the cookie means someone else, the next request is refused with SUBJECT_CHANGED instead of answered.
  • Any 401 makes it believe no one, so the reads asked after it learn who is signed in now. The application's update answers a read refused with SUBJECT_CHANGED with Remote.forget, which asks them; a refusal for any other reason (Your session ended.) is shown, since asking again would be refused again.
  • Believing no one is a gap: after a 401 or forget(), the next request is answered as whoever the cookie names. An application that keeps what Remote holds through a 401 (a session that ended, its old rows still shown) should forget them before another tab could sign in, or the next read merges the new account's answers into them. An answer to a request sent before the last 401 or forget() is never believed.
  • A sign-in or sign-out this tab makes calls belief.forget() in its Command, before update forgets what Remote holds, so the reads after it are not refused once first.

examples/auth wires all of it.