Auth / foldkit-auth
Sixty seconds
ts
import { Effect } from 'effect'
import { AuthServer } from 'foldkit-auth/server'
import { serveFetch } from 'foldkit-remote-server/fetch'
const http = { origin: 'https://app.example' } as const // the options given Http.make(AppAuth, http)
export const remote = serveFetch({
server, // RemoteServer.make(…)
resolvePrincipal: AuthServer.resolver({
auth: AppAuth, // Auth.make(…)
http,
principal: session => Effect.succeed({ id: session.subjectId }),
}),
layer: () => AppAuthLive, // AppAuth.layer, with its persistence
})AuthServer.resolver(config)is a declaration: it returns the functionserveFetchcalls per request, and throws at once ifhttpnames an origin that is not one (null, a trailing slash). Each call reads headers and asks the session store; it writes nothing.authis theAuth.make(…)value; the resolver yields it as a service, so the host'slayermust provide it. That is the one store, shared with the routes that set the cookie.httpis the same object givenHttp.make: the cookie's name, the trusted origins and the CSRF header are read from it, so the two agree.principalbuilds the application's principal from the verified session, per request. Read memberships fresh here, fromsession.subjectId; a session's claims are a snapshot taken at sign-in. It may refuse, withRemoteServer.unauthenticated(reason).
The client's side
Remote's transport posts every call, so a browser sends Origin on its own;
the CSRF header is the client's to add:
ts
import { Remote } from 'foldkit-remote'
const transport = Remote.httpWithLive('/remote', {
headers: () => ({ 'x-effect-auth-csrf': '1' }),
})A refusal reaches the Model as a failure; RemoteData.denied(error) from
foldkit-remote reads it as Unauthenticated with the reason below.